“数字经济”云安全公测大赛部分wp

gameapp

用模拟器登录抓包:

在击败大飞机前开启拦截,抓到数据包后,将Set-Cookie的值放到Cookie中请求,发现分数增加了30,则不断替换Cookie,将分数加到99999即可(开始打了个小飞机抓包替换Cookie,发现加了1分,以为只能加1分,结果用burp跑了一个小时,到比赛结束后才跑出来-_-)

使用burpsuite,配置宏操作即可使用intruder来做:

写脚本跑也是可以的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

url = 'http://121.40.219.183:9999/score/'

cookie = 'eyJwbGF5ZXIiOiJndGZseSIsInNjb3JlIjo5N30.XYYGIA.opFCsGqo33NMerDhFkEBODai9fA'
data = 'MISygCLch93NMojz/DaKAu88RkCQl2aTH/i0W0a3w0m1JBoEcr4YVuWdvb+hSSqWupieWqm0mDMbBdtJ2TWFeorLJKuF5S5J31lzVqKxeoq2h7PGuFqKiwJVtvA6uIdzjOrmkElvnlTysjE3Y06HjCe1x+T7s4zN0ahrEdOqC+8='

s = requests.session()
for i in range(1000000):
headers = {'Content-type': 'xxx', 'Cookie': 'session='+cookie, 'Connection': 'close'}
res = s.post(url, data=data, headers=headers)
print(res.text)
cookie_dic = requests.utils.dict_from_cookiejar(res.cookies)
cookie = cookie_dic['session']
if '{' in res.text:
print(headers)
print(res.text)
break

还有其他大佬直接反编译改飞机分数为100…tql

Inject4Fun

输入的usernamepassword会经过前端js加密后再发送到login.php。看wp说是道注入题;第一次碰到前端加密的题型,学习下思路

对于简单的前端加密,可以使用burpsuite来爆破。例如一道简单的经js前端加密的爆破题:

输入的密码会经过md5加密,那么在使用burp爆破时,需要设置将字典中的数据进行md5加密:

再爆破,会发现发送的password字段都经过md5加密了

除此之外,还可以使用python调用js代码来实现加密(当然python的crypto库很容易实现md5加密)。首先需要安装PyExecJS库:

sudo python3 -m pip install PyExecJS

通过编译js代码,再调用加密函数实现加密。例如实现md5加密:

1
2
3
4
5
import execjs

f = open('md5.js').read()
name = execjs.compile(f)
print(name.call('hex_md5', '123'))

剩下的爆破部分就不写了。回到这个题目上,在前端使用了很多的加密:

此时不便使用execjs来运行js代码了,运行起来会报错说缺少各种依赖~。有种简单的思路就是直接使用python的selenium库来调用浏览器实现自动化测试

安装(Ubuntu):

sudo python3 -m pip install selenium

使用的是chrome,查看chrome版本,并到http://chromedriver.storage.googleapis.com/index.html上下载对应的driver,将下载好的文件移动到/usr/bin即可

大致流程为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

browser = webdriver.Chrome()

browser.get('http://127.0.0.1/login.html')
username = browser.find_element_by_id('username')
username.clear() # 清空原有内容
username.send_keys('admin') # 输入用户名
time.sleep(1)
password = browser.find_element_by_id('password')
password.send_keys('123456') # 输入密码
time.sleep(1)
password.send_keys(Keys.ENTER) # 回车
time.sleep(1)
print(browser.page_source) # 打印出页面源码
browser.back() # 返回上一页面

当然,还有很多其他思路,参考文章

findme

附件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# coding=utf-8
import socket
import thread
import os

flag="xxx"

def remote_sub(conn, address):
print address,
(ip,port)=address
conn.settimeout(20)
secret=int(os.urandom(16).encode("hex"),16)
#conn.send(hex(secret))
ground=0
sky=pow(2,128)
for i in range(200):
conn.send("g\n")
newground=int(conn.recv(1024).strip(),16)
conn.send("s\n")
newsky=int(conn.recv(1024).strip(),16)
if newground<ground or newsky>sky or newground>newsky:
conn.close()
return
ground=newground
sky=newsky
if secret <ground or secret >sky:
conn.close()
return

conn.send("g1\n")
g1 = int(conn.recv(1024).strip(), 16)
conn.send("g2\n")
g2 = int(conn.recv(1024).strip(), 16)

if abs(g2-g1) > abs(sky-ground)/3+1:
conn.close()
return

if g1==secret and g2==secret:
conn.send(flag+"\n")
else:
if pow(abs(secret-g1)-abs(secret-g2),2)<pow(abs(g2-g1),2):
conn.send("1\n")
else:
conn.send("2\n")
conn.close()
return
def remote():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", 9999))
sock.listen(0)
while True:
thread.start_new_thread(remote_sub, sock.accept())
if __name__ == '__main__':
remote()

1.首先,随机生成了一个长度为16的字节串,将其16进制编码后再转为10进制:

secret=int(os.urandom(16).encode("hex"),16)

设置ground和sky初始值:

ground=0
sky=pow(2,128)

2.之后进入200次循环;首先判断接收的newground和newsky的值:

if newground<ground or newsky>sky or newground>newsky:
            conn.close()
            return

即需要满足下面条件才不会退出循环:

newground >= 0
newsky <= pow(2, 128)
newground <= newsky

即:

0 <= newground <= newsky <= pow(2, 128)

接着将ground和sky重新赋值为输入的值:

ground=newground
sky=newsky

3.又存在一个判断:

if secret <ground or secret >sky:
        conn.close()
        return

结合第2步,若要不退出循环需满足:

0 <= newground <= secret <= newsky <= pow(2, 128)

4.接收g1和g2后,又又存在一个判断:

if abs(g2-g1) > abs(sky-ground)/3+1:
            conn.close()
            return

即需要满足如下条件才不会退出:

|g2-g1| <= |(newsky - newground)|/3 + 1 

5.最后一个判断便是程序的关键:

if g1==secret and g2==secret:
    conn.send(flag+"\n")
else:
    if pow(abs(secret-g1)-abs(secret-g2),2)<pow(abs(g2-g1),2):
        conn.send("1\n")
    else:
        conn.send("2\n")

现假设:

g1=1
g2=9
secret=7

那么:

pow(abs(secret-g1)-abs(secret-g2),2)<pow(abs(g2-g1),2)
左边:pow(6-2, 2)
右边:pow(8, 2)

左边<右边,则会返回1,此时secret位于g1和g2中间的右边;

将g1增大为5,即g1和g2中间的位置,那么:

左边:pow(2-2, 2)
右边:pow(2, 2)

左边<右边,会返回1,此时secret位于g1和g2中间的右边

……

通过这个假设,则可发现可以使用二分法来不断缩小secret的范围(根据返回值为1,则说明secret位于g1和g2中间值右边,根据返回值为2,则说明secret位于g1和g2中间值左边),从而得到secret的值

由上述结论:

0 <= newground <= secret <= newsky <= pow(2, 128)
|g2-g1| <= |(newsky - newground)|/3 + 1 

可知,如果令newground=0newsky=pow(2,128),且g1=0,那么:

g2 = (newsky-newground)/3 + 1

由于范围除以三,那么此时g1~g20~(newsky-newground)/3 + 1,还剩下其余2/3没有检测到,因此此时可使用三分法来缩小secret范围:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# coding=utf-8
from pwn import *


def hexed(num):
return hex(num).replace('0x', '').replace('L','')


def judge(g1, g2):
ground = '0'
sky = '100000000000000000000000000000000' # hex(pow(2,128))

s.sendline(ground)
s.sendlineafter('s', sky)
s.sendlineafter('g1', hexed(g1))
s.sendlineafter('g2', hexed(g2))

result = s.recvlines(timeout=0.1)
print result

if '1' in result:
return 1
else:
return 0


s = remote('127.0.0.1', 9999)
newground = 0 # 左边界
newsky = pow(2, 128) # 右边界

while (newsky-newground)>3:
block = abs(newsky-newground)/3 + 1 # 分成三份

g1 = newground + block
g2 = g1 + block

# 三分法
flags = judge(newground, g1) # 左

if flags:
newsky = g1
else:
flags = judge(g1, g2) # 中
if flags:
newground = g1
newsky = g2
else: #右
newground = g2


# 找到secret最小的范围,逐一尝试
for i in range(newsky-newground):
judge(newground+i, newground+i)