【PoRE】Lab7: Packet Sniffing

回到目录

内容总结

  • 这一课主要围绕着应用层协议HTTP、传输层协议TCP和UDP展开的,并且介绍了BurpSuite这一工具。大部分内容应该和《计算机网络安全》(名字可能每届会改)课程有所重复。

Lab简介与参考

  • 这个Lab一共分成两个部分,都会围绕着BurpSuite展开。
  • Task 1.1: Find two secrets in the app
      Task 1需要我们输入一个用户名和密码。
    图1: 初始页面
      最开始漫无头绪,先随意输入一个内容后发送,用BurpSuite拦截返回的应答包,发现是一串没有意义的字符串,这就联想到可能有加密和解密的操作。于是使用jadx反编译apk,发现有调用BabyCipher.decode()进行解密。将返回到的内容解密一下:
    图2: 随意输入后的结果
      提示我们,试图用GUEST进行登录。于是继续试探,将用户名改为GUEST,密码随意输入:
    图3: 先用GUEST作为用户名登录
      发现还有提示,提示我们密码是TEMP_PASSWD!是不是觉得这个Task 1就如此简单呢?显然并不可能。将用户名和密码改为提示一致时,发现每次返回的结果仍是图3所示的结果。
      这就十分令人震惊了,但事出有因——代码里一定有“陷阱”!于是查看代码,发现了一个问题:
    图4: 代码中的小陷阱
      这里调用的一个replace十分显眼,而我们输入的密码(TEMP_PASSWD)中,恰有下划线’_’,这就会被换成’#’,于是我们屡次尝试只能屡次失败。之后就要解决这个问题。
      事实上这个问题至少可以有两种解决方案:一个是通过BurpSuite拦截和修改报文,这个方案应该是本Lab的初衷。不过我当时没有想到这一点,现在也没有进行测试,将发送报文中的被替换成#的密码换回去。
      这里我当时使用了第二个方案:修改代码。既然罪魁祸首是这个replace,把它给换了就行。于是前往修改Smali代码:
    图5: 修改Smali代码去除replace()
      将这里面万恶的replace()调用给注释掉。随后运行就能顺利得到flag了!

  关于BurpSuite拦截和修改报文的方法,大家可以查看另一篇学姐写的博客。链接见注释1。简单来说,就是勾选Proxy中Interception is on,然后直接修改拦截下来的请求和响应报文。

  • Task 1.2: Buy secret
      进入Task 1的第二个阶段,需要我们去“购买”密钥。
    图6: Task1.2的初始页面
      此时点击按钮,会显示“WHO ARE YOU?”。这个结果也不奇怪,因为上面页面显示的学号有误。同样地,也可以通过修改发送的报文以修改学号,但这里与之前一致,诉诸Smali代码的修改来实现。
    图7: 去修改学号
      随后继续发送,返回的报文会提示金钱不够。于是去修改代码中的金钱部分。
    图8: 去修改金钱
      继续发送,发现返回的flag仍不理想,并且得到了来自助教的嘲讽(这张图一定得贴出来!)!
    图9: 错误的flag
      问题在哪呢?发现在启动的SecretActivity中的onClick()函数内,找到了一个is_fake的选项,并且初始化还是1。这个应该就是问题所在了……继续修改Smali代码:
    图10: 修改is_fake
      最后就能成功了!

  以修改Smali代码的方法破解的话,最后的UI会显示出我们修改的学号、金钱数。这个与Task 2就会产生冲突。使用BurpSuite拦截修改的话就不会有这个问题。

  • Task 2: Write a Burp Suite extension
      这个Task可能是继Android Programming之后最难的一个Task了,因为要求我们去写一个BurpSuite的插件。尽管助教很善良地给了我们一些参考文档,但是想要迅速地啃懂那些参考文档,的确需要耐心。
      关于BurpSuite插件的一些参考文档,BurpSuite本身就已经提供了不少。在Extender - APIs下可以找到。
    图11: BurpSuite本身提供的一些帮助文档
      因此对于我来说,这一个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=xxxxxxxxxxx&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\":\"xxxxxxxxxxx\",\"Secret1\":\"flag{e43y_p4ck37_sn1ff1Ng}\",\"money\":1}";
            stringBuilder.append(encode(helpers.stringToBytes(body)));
            byte[] returnResponse = helpers.stringToBytes(stringBuilder.toString());
            request.setResponse(returnResponse);
        }
    }
}

  至此完成了本Lab的所有内容。

写在最后

  • 个人认为,Task 2的难度从某些程度上可以媲美Android Programming,它们的共同点都是基于APIs的开发,这个对于我们来说还比较陌生——很少接触实战环境,所以也是一个很好的成长经验,也很容易上头。我的室友凌晨三点几近彻夜未归,正是因为这个Lab。
    附图1
    那个左下角鬼鬼祟祟冒个头的3点提交的,便是我的室友。这系列博客写完之后,我分享之余,他还特地要求我,加上这段轶事。我想,既是他点名道姓地要加上,我便认认真真地给他写上一段罢。

  中秋之后,秋风是一天凉比一天,看着将近初冬;于是我便早些熄灯上床,准备第二天的体育课了。那天的晚上,只我一人还醒着,我正合了眼准备睡着。忽然间听得一个声音,“我回来了。”这声音虽然极低,却很耳熟。看时又全没有人。坐起来向下一望,那大白牙便露了出来,在书桌前摆着。他脸上黑,穿一件单衣,拉开椅子,把整日为伴的电脑提了出来,还将电源仔仔细细地插上;见了我,又说道,“还没睡呢。”另个室友也醒了过来,一面说:“你回来了?不知你写完Lab了没有。”那室友很颓唐的仰面答道,“这……也快写完罢。还差些许润色,就快好。”我仍然同平常一样,笑着对他说,“你今天又是写不完了!”但他这回却不十分分辩,单说了一句“不要取笑!”“取笑?要是写完,怎么还开电脑?”室友低声说道,“润色,润,润……”他的眼色,很像恳求我们,不要再提。此时别的寝室都已熄灯了,我们两个就寝的便又睡了。
  自此之后许久,我尚不得入眠,只听得键盘声悉悉窣窣之余,还夹杂几句抱怨声。后来又是一个小时,终于是没了声音——他大约的确是写完了。


  1. 请点击我 ↩︎

  2. 如果您和我一样,也是在Task 1中通过修改Smali代码实现的,那么请在Task 2中使用最初始的apk,否则会有干扰。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值