回到目录
内容总结
- 这一课主要围绕着应用层协议HTTP、传输层协议TCP和UDP展开的,并且介绍了BurpSuite这一工具。大部分内容应该和《计算机网络安全》(名字可能每届会改)课程有所重复。
Lab简介与参考
- 这个Lab一共分成两个部分,都会围绕着BurpSuite展开。
-
Task 1.1: Find two secrets in the app
Task 1需要我们输入一个用户名和密码。
最开始漫无头绪,先随意输入一个内容后发送,用BurpSuite拦截返回的应答包,发现是一串没有意义的字符串,这就联想到可能有加密和解密的操作。于是使用jadx反编译apk,发现有调用BabyCipher.decode()进行解密。将返回到的内容解密一下:
提示我们,试图用GUEST进行登录。于是继续试探,将用户名改为GUEST,密码随意输入:
发现还有提示,提示我们密码是TEMP_PASSWD!是不是觉得这个Task 1就如此简单呢?显然并不可能。将用户名和密码改为提示一致时,发现每次返回的结果仍是图3所示的结果。
这就十分令人震惊了,但事出有因——代码里一定有“陷阱”!于是查看代码,发现了一个问题:
这里调用的一个replace十分显眼,而我们输入的密码(TEMP_PASSWD)中,恰有下划线’_’,这就会被换成’#’,于是我们屡次尝试只能屡次失败。之后就要解决这个问题。
事实上这个问题至少可以有两种解决方案:一个是通过BurpSuite拦截和修改报文,这个方案应该是本Lab的初衷。不过我当时没有想到这一点,现在也没有进行测试,将发送报文中的被替换成#的密码换回去。
这里我当时使用了第二个方案:修改代码。既然罪魁祸首是这个replace,把它给换了就行。于是前往修改Smali代码:
将这里面万恶的replace()调用给注释掉。随后运行就能顺利得到flag了!
关于BurpSuite拦截和修改报文的方法,大家可以查看另一篇学姐写的博客。链接见注释1。
-
Task 1.2: Buy secret
进入Task 1的第二个阶段,需要我们去“购买”密钥。
此时点击按钮,会显示“WHO ARE YOU?”。这个结果也不奇怪,因为上面页面显示的学号有误。同样地,也可以通过修改发送的报文以修改学号,但这里与之前一致,诉诸Smali代码的修改来实现。
随后继续发送,返回的报文会提示金钱不够。于是去修改代码中的金钱部分。
继续发送,发现返回的flag仍不理想,并且得到了来自助教的嘲讽(这张图一定得贴出来!)!
问题在哪呢?发现在启动的SecretActivity中的onClick()函数内,找到了一个is_fake的选项,并且初始化还是1。这个应该就是问题所在了……继续修改Smali代码:
最后就能成功了!
以修改Smali代码的方法破解的话,最后的UI会显示出我们修改的学号、金钱数。这个与Task 2就会产生冲突。使用BurpSuite拦截修改的话就不会有这个问题。
-
Task 2: Write a Burp Suite extension
这个Task可能是继Android Programming之后最难的一个Task了,因为要求我们去写一个BurpSuite的插件。尽管助教很善良地给了我们一些参考文档,但是想要迅速地啃懂那些参考文档,的确需要耐心。
关于BurpSuite插件的一些参考文档,BurpSuite本身就已经提供了不少。在Extender - APIs下可以找到。
因此对于我来说,这一个Task也是一次学习的经历:组织已有的APIs进行开发,这个也更符合真实情境。因此我也建议读者们能够自己尝试一次,如果尝试有误再诉诸帮助。如果您看到了这里,建议暂停,自己尝试一次。
助教本身提供了一个实现IHttpListener接口的类的“模板”,不过当时我没有看到,于是从零开始写了一个实现IProxyListener接口的类,也是可以跑通的。这里不多做解释,直接贴代码了。如果有关于函数本身的问题,可以在图11所示的BurpSuite提供的APIs里查阅。2
package burp;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
public class BurpExtender implements IBurpExtender, IProxyListener {
private static final String SecretChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
private IExtensionHelpers helpers;
private int flag;
private final String name = "PoRE's BurpExtender";
private static String encode(byte[] bArr) {
int i;
StringBuffer stringBuffer = new StringBuffer(((bArr.length + 7) * 8) / 5);
int i2 = 0;
int i3 = 0;
while (i2 < bArr.length) {
int i4 = bArr[i2] >= 0 ? bArr[i2] : bArr[i2] + 256;
if (i3 > 3) {
i2++;
i3 = (i3 + 5) % 8;
i = ((i4 & (255 >> i3)) << i3) | ((i2 < bArr.length ? bArr[i2] >= 0 ? bArr[i2] : bArr[i2] + 256 : 0) >> (8 - i3));
} else {
int i5 = i3 + 5;
i = (i4 >> (8 - i5)) & 31;
i3 = i5 % 8;
if (i3 == 0) {
i2++;
}
}
stringBuffer.append(SecretChars.charAt(i%32));
}
return stringBuffer.toString();
}
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
helpers = callbacks.getHelpers();
callbacks.setExtensionName(name);
callbacks.registerProxyListener(this);
}
@Override
public void processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessage message) {
IHttpRequestResponse request = message.getMessageInfo();
if (messageIsRequest) {
IRequestInfo analyzedRequest = helpers.analyzeRequest(request);
String url = analyzedRequest.getUrl().toString();
if ("http://49.235.197.28:80/lab7/login.php".equals(url)) {
//TASK 2.1
flag=0;
byte[] requestBytes =
helpers.updateParameter(request.getRequest(), helpers.buildParameter("msg",
encode(helpers.stringToBytes("username=GUEST&password=TEMP_PASSWD")),
IParameter.PARAM_BODY));
request.setRequest(requestBytes);
}
else if ("http://49.235.197.28:80/lab7/buySecret.php".equals(url)) {
//TASK 2.2
flag=1;
byte[] requestBytes =
helpers.updateParameter(request.getRequest(), helpers.buildParameter("msg",
encode(helpers.stringToBytes("user_id=19307130005&money=12345&is_fake=0")),
IParameter.PARAM_BODY));
request.setRequest(requestBytes);
}
else {
// Other cases. Ignore it.
return;
}
}
else {
if (flag == 1) {
return;
}
byte[] responseBytes = request.getResponse();
IResponseInfo analyzedResponse = helpers.analyzeResponse(responseBytes);
int offset = analyzedResponse.getBodyOffset();
StringBuilder stringBuilder = new StringBuilder();
for (int i=0;i<offset;i++) {
stringBuilder.append((char)responseBytes[i]);
}
String body = "{\"result\":1,\"message\":\"success\",\"id\":\"19307130005\",\"Secret1\":\"flag{e43y_p4ck37_sn1ff1Ng}\",\"money\":1}";
stringBuilder.append(encode(helpers.stringToBytes(body)));
byte[] returnResponse = helpers.stringToBytes(stringBuilder.toString());
request.setResponse(returnResponse);
}
}
}
至此完成了本Lab的所有内容。