This page looks best with JavaScript enabled

bugku代码审计

 ·  ☕ 5 min read · 👀... views

%0a绕过

1
2
3
4
5
6
if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
    echo '1st ok'."<br>";
}
else{
    die('23333333');
}

%0A绕过(%0A经URL编码后是回车)

tac

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
$query = $_SERVER['QUERY_STRING'];
if (strlen($cmd) > 8){
    die("too long :(");
}

if( substr_count($query, '_') === 0 && substr_count($query, '%5f') === 0 ){
    $arr = explode(' ', $cmd);
    if($arr[0] !== 'ls' || $arr[0] !== 'pwd'){
        if(substr_count($cmd, 'cat') === 0){
            system($cmd);
        }
        else{
            die('ban cat :) ');
        }
    }
    else{
        die('bad guy!');
    }
}
else{
    die('nonono _ is bad');
}

禁用cat ls pwd
system(tac f*)
linux tac命令


这里相当于system(tac f*)
此题system(tac fl*)也可以

MD5绕过

0e绕过

练习地址
http://chinalover.sinaapp.com/web17/index.php?a=s1885207154a&b=s1836677006a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php 

if (isset($_GET['a']) && isset($_GET['b'])) {
    $a = $_GET['a'];
    $b = $_GET['b'];
    if ($a != $b && md5($a) == md5($b)) {
        echo "flag{XXXXX}";
    } else {
        echo "wrong!";
    }

} else {
    echo 'wrong!';
}

?>

上面只要传入参数a=s1885207154a,b=s1836677006a,即可,为什么呢?看一下这两个字符串的md5值可以返现分别如下:

1
2
3
MD5值
md5("s1885207154a") => 0e509367213418206700842008763514
md5("s1836677006a") => 0e481036490867661113260034900752

二者都是0e开头,在php中0e会被当做科学计数法,就算后面有字母,其结果也是0,所以上面的if判断结果使true,成功绕过

preg_replace函数

题目(xctf ics-05)(攻防世界有复现)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php
//方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试
if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {

    echo "<br >Welcome My Admin ! <br >";

    $pattern = $_GET[pat];
    $replacement = $_GET[rep];
    $subject = $_GET[sub];

    if (isset($pattern) && isset($replacement) && isset($subject)) {
        preg_replace($pattern, $replacement, $subject);
    }else{
        die();
    }

}
?>
函数作用:搜索subject中匹配pattern的部分, 以replacement进行替换。
$pattern: 要搜索的模式,可以是字符串或一个字符串数组。
$replacement: 用于替换的字符串或字符串数组。
$subject: 要搜索替换的目标字符串或字符串数组。
preg_replace函数存在命令执行漏洞

此处明显考察的是preg_replace 函数使用 /e模式,导致代码执行的问题。

参考[https://www.cnblogs.com/dhsx/p/4991983.html]

/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。

也就是说,pat和sub有相同部分,rep的代码就会执行。

根据源码分析X-Forwarded-For改成127.0.0.1之后,GET进三个参数。然后调用了preg_replace函数。并且没有对pat进行过滤,所以可以传入"/e"触发漏洞

最终结果
在这里插入图片描述

extract变量覆盖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan)){
	$content=trim(file_get_contents($flag));
	if($shiyan==$content){
		echo'flag{xxx}';
	}else{
		echo'Oh.no';
	}
}

代码大概的意思是可以从get获得的参数,设置入GET超全局数组里面,并且覆盖之前的变量

这样子只需要重新设置$shiyan 和 $content,绕过if的检测就可以了

、

strcmp比较字符串

1
2
3
4
5
6
7
8
9
<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
	if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
	//比较两个字符串(区分大小写)
		die('Flag: '.$flag);
	else
		print 'No';
}

传数组

url二次编码绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
if(eregi("hackerDJ",$_GET[id])) {
	echo("not allowed!");
	exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ"){
	echo "Access granted!";
	echo "flag";
}
  • ergei() 函数正则匹配 等于erge()函数 只是匹配的时候忽略大小写


需要匹配 hackerDJ 只要在他url编码后任意一个编码前加上25就行 %25 url解码后是 %

md5函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
error_reporting(0);
$flag = 'flag{test}';
if (isset($_GET['username']) and isset($_GET['password'])) {
	if ($_GET['username'] == $_GET['password'])
		print 'Your password can not be your username.';
	else if (md5($_GET['username']) === md5($_GET['password']))
		die('Flag: '.$flag);
	else
		print 'Invalid password';
}

0e绕过好像没用 直接数组绕过

数组返回NULL绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
$flag = "flag";
if (isset ($_GET['password'])) {
	if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
		echo 'You password must be alphanumeric';
	else if (strpos ($_GET['password'], '--') !== FALSE)
		die('Flag: ' . $flag);
	else
		echo 'Invalid password';
}

弱类型整数大小比较绕过

1
2
3
4
5
<?php
$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336)
	echo $flag;

科学计数法 也可以传数组

sha()函数比较绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password'])){
	var_dump($_GET['name']);
	echo "";
	var_dump($_GET['password']);
	var_dump(sha1($_GET['name']));
	var_dump(sha1($_GET['password']));
	if ($_GET['name'] == $_GET['password'])
		echo 'Your password can not be your name!';
	else if (sha1($_GET['name']) === sha1($_GET['password']))
		die('Flag: '.$flag);
	else
		echo 'Invalid password.';
}else{
	echo 'Login first!';
}
  • var_dump() 打印变量相关信息
  • sha1() 计算字符串的 sha1 散列值

数组绕过

md5加密相等绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
	if ($a != 'QNKCDZO' && $md51 == $md52) {
		echo "flag{*}";
	} else {
		echo "false!!!";
	}
}else{
	echo "please input a";
}

虽然说不用看也知道一定是0e绕过。。。。

十六进制与数字比较

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
error_reporting(0);
function noother_says_correct($temp)
{
	$flag = 'flag{test}';
	$one = ord('1'); //ord — 返回字符的 ASCII 码值
	$nine = ord('9'); //ord — 返回字符的 ASCII 码值
	$number = '3735929054';
	// Check all the input characters!
	for ($i = 0; $i < strlen($number); $i++){
	// Disallow all the digits!
		$digit = ord($temp{$i});
		if ( ($digit >= $one) && ($digit <= $nine) ){
		// Aha, digit not allowed!
			return "flase";
		}
	}
	if($number == $temp)
		return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);

变量覆盖(平台挂掉了)

ereg正则%00截断

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
$flag = "xxx";
if (isset ($_GET['password'])){
	if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE){
		echo 'You password must be alphanumeric';
	}else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999){
		if (strpos ($_GET['password'], '-') !== FALSE){ //strpos — 查找字符串首次出现的位置
			die('Flag: ' . $flag);
		}else{
			echo('- have not been found');
		}
	}else{
		echo 'Invalid password';
	}
}

法1.php对字符串是数字的部分进行截取进行判断 还有就是 erge %00截断匹配了

法2.数组返回 null null !== false

strpos数组绕过

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {
	if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)
		echo '必须输入数字才行';
	else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)
		die('Flag: '.$flag);
	else
		echo '骚年,继续努力吧啊~';
}

跟上一题一样 没什么好解释

数字验证正则绕过

 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
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD']){
	$password = $_POST['password'];
	if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)){ //preg_match — 执行一个正则表达式匹配
		echo 'flag';
		exit;
	}
	while (TRUE){
		$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
		if (6 > preg_match_all($reg, $password, $arr))
			break;
		$c = 0;
		$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母
		foreach ($ps as $pt){
			if (preg_match("/[[:$pt:]]+/", $password))
			$c += 1;
		}
		if ($c < 3) break;	//>=3,必须包含四种类型三种与三种以上
		if ("42" == $password) echo $flag;
		else echo 'Wrong password';
		exit;
	}
}

要长度超过12字母符号数字大小写超过三种 但是实际测试符合条件的都不行 不符合条件的就直接出flag 不懂不懂。。。。。

网上版本都是直接post空值就行 应该是哪里出了问题?题目本意应该不是这个?

简单的waf(靶机挂了)

Share on

ruokeqx
WRITTEN BY
ruokeqx