H&NCTF2024-Re-Ezshoping(网络商城apk抓包逆向)

wp拜读:[原创]H&NCTF RE 部分题解-CTF对抗-看雪-安全社区|安全招聘|kanxue.com
注:由于本题需要远程服务环境,所以无法复现只能通过分析伪代码加大佬的wp来理解这题了!

0.锁定关键伪代码

根据购买按钮的位置找到处理flag的逻辑:

这里点击就可以触发购买验证!

1.锁定发送网络请求的代码

继续向下找逻辑!
这个函数就算发送网络请求的函数了比较复杂:

下面就来一层层解析一些它!

a.整理复杂伪代码,并进行分析

先用chatgpt优化一下代码!

    private void verifyPurchase(final String username, final double amount, final String signature) {
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        StringRequest stringRequest = new StringRequest(
            Request.Method.POST,//参数一
            PURCHASE_URL,、、参数二
            new Response.Listener<String>() {//**匿名内部类**
                @Override
                public void onResponse(String response) {
                    // 处理成功响应
                    showPurchaseResult(response);
                }
            },
            new Response.ErrorListener() {//**匿名内部类**
                @Override
                public void onErrorResponse(VolleyError error) {
                    // 处理错误响应
                    handleError(error);
                }
            }
        ) {
            @Override   //重写StringRequest类的getParams方法
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("username", username);
                params.put("amount", String.format("%.2f", amount));
                params.put("signature", signature);
                return params;
            }
        };

        // 将请求添加到请求队列
        requestQueue.add(stringRequest);
    }

再简化一下代码结构:

private void verifyPurchase(final String str, final double d, final String str2)
{
	//申请一个网络请求对象
	RequestQueue requestQueue = Volley.newRequestQueue(this);
	//创建这个网络请求的数据
	StringRequest stringRequest = new StringRequest(
						POST, URL.pURL, new R.L(){},new R.ErrorL() {}
	)
	{
		//相当于设置网络请求的参数
	}
	//加入网络请求队列!
	Volley.newRequestQueue(this).add(stringRequest)
}

这段代码简写出来就是这样:
通过Volley.newRequestQueue(this).add来添加网络请求,通过StringRequest构造要发送的请求参数,和处理请求放回的结果,这里是一个http请求,请求方法是post!下面来研究不同http返回的处理流程!

b.整理http请求返回的异常值

来看一下http请求返回error的处理方式:

直接让chatgpt整理一下Error返回值的处理方式:

  • 402 Payment Required
    • 显示消息 “Insufficient funds to complete the purchase.”-资金不足,无法完成购买。
  • 403 Forbidden
    • 显示一个对话框,通知用户禁止访问的错误。
  • 404 Not Found
    • 显示消息 “User not found.”
  • 默认处理
    • 显示通用错误消息。
  • 无响应处理
    • 处理网络错误,未接收到响应。

下面分析:
发送的数据是用户名、资金、apk程序的特征值,可以通过抓包来知道发送的post请求参数!
直接白嫖大佬的图片:

c.整理http请求返回成功值后的操作


这里就很简单了,得到正确的回应后,app页面就会弹出网络请求收到的数据!!
如果收到flag自然也就会弹出flag!

2.分析后发现flag存储在服务器

通过抓包可以知道发送服务器的数据是什么格式!
所以直接手动用python在模拟一次发送数据包!

import socket
 
# 指定服务器地址和端口
server_address = ('hnctf.imxbt.cn', 20528)
 
# 指定表单数据
form_data = {
    # 这里应该填入POST请求的具体数据
        "Money": "114514.00",
    "signature": "376c4fe518240bc513f67bf477d5d950d757d51bb58db594fa4551e248364413",
    "username": ""  #填自己的用户名即可
}
 
# 将表单数据转换为application/x-www-form-urlencoded格式
form_data_encoded = "&".join("{}={}".format(key, val) for key, val in form_data.items())
 
# 准备HTTP请求头
http_request = """POST /purchase HTTP/1.1\r
Host: hnctf.imxbt.cn:20528\r
If-None-Match: W/"12-hfcD7BKoo9fJ4GgYnq9Rj3aNpD8"\r
Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r
User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; PCRT00 Build/PQ3A.190605.01231654)\r
Connection: Keep-Alive\r
Accept-Encoding: gzip\r
Content-Length: {}\r
\r
""".format(len(form_data_encoded))
 
# 完整的HTTP请求数据
http_request += form_data_encoded
 
# 创建TCP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
# 连接到服务器
sock.connect(server_address)
 
# 发送HTTP请求
sock.sendall(http_request.encode())
 
# 接收响应数据
response = sock.recv(4096)
print(response.decode())
 
# 关闭socket连接
sock.close()

发送过去后会有两种回显:
一个是:Did you cheat with this much money?!
另一个是:Not enough money!!
出题人给了金额的上限200000,那么获得flag 的逻辑也就出来了,发送出正确的金额就可以获得flag!
直接就可以使用二分法来爆破出金额,最后得到金额是114514.00

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 61
ETag: W/"3d-lbjcXjt9Oql9sd2OEm6pVRILsSE"
Date: Thu, 16 May 2024 01:31:23 GMT
Connection: keep-alive
Keep-Alive: timeout=5
 
H&NCTF{Congratulati0ns!_3cad3260-0c7e-4d98-afbc-814cc5221fcc}

下面就是二分法的爆破脚本:

import requests
from time import sleep

def check_money(money):
    url = 'http://103.8.69.140:3000/purchase'
    data = {
        "username": "1",
        "Money": money,
        "signature": "376c4fe518240bc513f67bf477d5d950d757d51bb58db594fa4551e248364413"
    }
    headers = {
        "Content-Type": "application/json"
    }
    try:
        response = requests.post(url, json=data, headers=headers)
        return response.text, response.status_code
    except requests.exceptions.RequestException as e:
        print(f"Network error: {e}")
        return None, None

def find_correct_money(low, high):
    attempts = 0
    while low <= high:
        mid = (low + high) // 2
        print(f"Trying money: {mid}")
        response_text, status_code = check_money(mid)
        if response_text is None or status_code is None:
            print("Failed to get response, retrying...")
            sleep(2)  # Wait for 2 seconds before retrying
            attempts += 1
            if attempts > 5:  # Maximum 5 retries
                print("Too many failed attempts, aborting.")
                return None
            continue

        if "H&NCTF" in response_text:
            print("Flag found:", response_text)
            return mid
        elif "Not enough money" in response_text:
            low = mid + 1
        elif "Did you cheat with this much money" in response_text or "Invalid signature" in response_text:
            high = mid - 1
        else:
            print(f"Unexpected response: {response_text}, status code: {status_code}")
            break
        attempts = 0
    return None

# Example usage
if __name__ == "__main__":
    flag_money = find_correct_money(1, 200000)
    if flag_money is not None:
        print(f"The correct money value is: {flag_money}")
    else:
        print("Failed to find the correct money value")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值