北京林业大学登录系统分析 | 原创,AI翻译

Home PDF

这篇文章最初在中文中撰写并发布在CSDN上。


本文详细介绍了对北京林业大学网络登录系统的逆向工程过程。目标是通过程序模拟登录过程,有效地仿真用户通过网页浏览器连接到网络的操作。

通过使用Chrome的开发者工具,可以观察到登录过程中的网络请求。

第一个请求是发送到 CheckLogin.jsp,随后由 CheckLogin.jsp 触发对 index.jsp 的请求。

让我们更仔细地看看 CheckLogin.jsp

可以看到,它使用了一个POST请求并且包含了几个键值对。但 action 是什么呢?

通过检查开发者工具中的“表单数据”,可以查看源代码:

要找到 action 的实际值,可以检查页面源代码:

action 值是第二行中的字符串。

现在,如何获取IP地址?登录系统可以在校园的任何地方访问,无论是通过Wi-Fi还是寝室的有线连接。IP地址是动态的。如何自动获取它?

还记得第一张图片吗?

网页会自动提供IP地址。登录系统知道哪个IP在访问它。我们可以从网页中提取它。

Chrome提供了方便的工具,可以快速定位网页代码的特定部分。Firefox有类似的插件,称为Firebug。

使用“检查元素”工具(放大镜图标),可以点击页面上的IP地址。

开发者工具将显示HTML结构,揭示IP地址在带有类 login_txt<span> 标签中,具体位于其文本内容中。

Jsoup的 select 函数可以查找匹配CSS查询的元素,而 first() 返回第一个匹配的元素。

有了所有的键值对,我们现在可以模拟登录过程。

POST请求在请求体中发送键值对。post.abort() 调用中断了请求。这是因为我们将重用 httpClient 进行后续请求。org.apache.http 类尽量重用HTTP连接。如果请求没有终止,使用相同连接发送另一个请求可能会导致异常。

为什么我们需要重用 httpClient?我稍后会解释。

提交到 checkLogin.jsp 并不足以连接到网络。这个JSP只检查用户名和密码是否正确。

通过添加一个打印语句,可以看到响应代码。

200响应表示成功登录,303表示凭据不正确,404表示连接错误。

执行的第二个JSP脚本是 index.jsp,这是一个GET请求。

在这之后,我们仍然无法连接到网络。我们需要模拟请求到 connect_action.jsp,它需要一个 userid 参数(例如,userid=88888),对应于学生的ID。我注意到,前一个学生的 userid 仅比我的小1。如何获取这个值?

幸运的是,我记得我们从网页中提取了IP地址。我们可以做同样的事情来获取 userid

这张截图是从断开连接页面获取的,但相同的逻辑适用于 connect.jsp。第二个JSP返回的页面的源代码包含了下一个我们需要请求的JSP的键值对。

在这里,我们使用正则表达式。group(0) 是整个匹配(例如,userid=88888),group(1) 是括号内的内容(例如,88888)。\d 匹配任何数字,+ 表示一个或多个。find() 检查表达式是否匹配字符串的任何部分,而 matches() 检查表达式是否匹配整个字符串。因此,如果 src 类似于 <frame userid=88888&ip="matches() 将返回 false,因为正则表达式不匹配整个字符串。

这是Java代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Login{

	static void print(String format, Object... args) {
		System.out.println(String.format(format, args));
	}

	public static void main(String[] args) {
		HttpClient httpClient = new DefaultHttpClient();
		String ip;
		String userId;
		String username="130888888";
		String password = "88888888";

		ip=cssQueryFirstText("http://login.bjfu.edu.cn/index.jsp","span.login_txt");

		doPost(httpClient,"http://login.bjfu.edu.cn/checkLogin.jsp",
				"username",username,"password",password,
				"ip",ip,"action","checkLogin.jsp");
		String content=doGet(httpClient,"http://login.bjfu.edu.cn/user/index.jsp",
		  "ip",ip,"action","connect");
		userId=userId(content);
		doGet(httpClient,"http://login.bjfu.edu.cn/user/network/connect_action.jsp",
			"userid",userId,"ip",ip,"type","2");
	}

	static String userId(String html){
		Document doc=Jsoup.parse(html);
		Element elem=doc.select("frame#main").first();
		String src=elem.attr("src");
		Pattern pattern=Pattern.compile("userid=(\\d+)");
		Matcher matcher=pattern.matcher(src);
		String ans="";
		if(matcher.find()){
		  ans=matcher.group(1);
		}
		return ans;
	}

	static String cssQueryFirstText(String url,String cssQuery) {
		String ip=null;
		try{
			Document doc=Jsoup.connect(url).get();
			Elements elems=doc.select(cssQuery);
			Element elem=elems.first();
			ip=elem.text();
		}catch(Exception e){
			e.printStackTrace();
		}
		return ip;
	}

	static String doGet(HttpClient httpClient, String url, String... pairs) {
		String entityContent=null;
		try {
			url = makeGetSrl(url, pairs);
			HttpGet get = new HttpGet(url);
			HttpResponse response = httpClient.execute(get);
			//print("%d", response.getStatusLine().getStatusCode());
			entityContent = entity(response);
			EntityUtils.consume(response.getEntity());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return entityContent;
	}

	static void printEntity(HttpResponse rp){
		print("%s",entity(rp));
	}

	static String entity(HttpResponse response) {
		StringBuilder sb = new StringBuilder("");
		try {
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				BufferedReader br = new BufferedReader(new InputStreamReader(
						entity.getContent()));
				String line = null;
				while ((line = br.readLine()) != null) {
					sb.append(line + "\n");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

	static String makeGetSrl(String url,String... pairs) {
		if(!url.endsWith("?")){
			url+="?";
		}
		List<NameValuePair>params=new LinkedList<NameValuePair>();
		int len=pairs.length;
		for(int i=0;i<len/2;i++){
			params.add(new BasicNameValuePair(pairs[2*i],pairs[2*i+1]));
		}
		String paramsStr=URLEncodedUtils.format(params,"utf-8");
		url+=paramsStr;
		return url;
	}

	static String doPost(HttpClient httpClient, String url, String... pairs) {
		String entityContent = null;
		try {
			HttpPost post = new HttpPost(url);
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			for (int i = 0; i < pairs.length / 2; i++) {
				params.add(new BasicNameValuePair(pairs[2 * i], pairs[2 * i + 1]));
			}
			post.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
			HttpResponse response = httpClient.execute(post);
			entityContent = entity(response);
			//print("%d", response.getStatusLine().getStatusCode());
			post.abort();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return entityContent;
	}

	private static String getCookies(HttpClient client) {
        StringBuilder sb = new StringBuilder();
        List<Cookie> cookies = ((AbstractHttpClient)
        		client).getCookieStore().getCookies();
        for(Cookie cookie: cookies)
            sb.append(cookie.getName() + "=" + cookie.getValue() + ";");
        return sb.toString();
   }
}

完整的源代码可以在GitHub上找到。请注意,您可能需要一个有效的大学网络账户才能运行它。

重用相同的 HttpClient 的原因是它会自动存储cookie。JSP脚本使用cookie来确定请求是否来自同一个会话。这就是为什么从淘宝复制一个URL到另一个浏览器可能会导致超时错误。

jsoup 和正则表达式是非常有用的工具。有在线工具可以练习正则表达式。享受使用它们吧!


Back 2025.06.01 Donate