๋ฌธ์ : DreamHack โ Run ๋ถ๋ฅ: reversing ๋์ด๋: ๐ Platinum 4 FLAG:
GoN{run_length_encoding}
๋ฌธ์ ์ค๋ช ์ ์ด๊ฒ ์ ๋ถ๋ค.
Time is running out. There's nowhere to run. You need to run this program. So run. RUN. NOW
ํํธ๋ ์๊ณ , ์ฒจ๋ถ๋ BGM ๋งํฌ ํ๋๊ฐ ๋ค์ด๋ค. 2022 Spring GoN Open Qual CTF ์์ ๋์ด์จ ๋ฌธ์ ๋ผ
ํ๋๊ทธ ์ ๋์ฌ๋ ๋๋ฆผํต ๊ด๋ก์ธ DH ๊ฐ ์๋๋ผ GoN ์ด๋ค. ์ด๊ฑธ ๋ชจ๋ฅด๊ณ DH ๋ก ์์ํ๋ ๋ฌธ์์ด๋ง
์ฐพ์ผ๋ฉด ๋๊น์ง ์๋ฌด๊ฒ๋ ๋ชป ์ฐพ๋๋ค.
๋ฐ์ ๊ฑด ํ์ผ ๋ ๊ฐ๋ฟ์ด๋ค.
file extracted/main extracted/flag.enc; ls -l extracted; readelf -h extracted/main | grep -E "Type|Entry|Machine"
flag.enc ๋ฅผ ๋๊ณ file ์ด "OpenPGP Public Key" ๋ผ๊ณ ๋ตํ๋๋ฐ, ์ด๊ฑด ์ฒซ ๋ฐ์ดํธ ํ๋๊ฐ ์ฐ์ฐํ
๊ฒน์ณ์ ๋์จ ์คํ์ด๋ค. ์ค์ ๋ก๋ PGP ์ ์๋ฌด ์๊ด์ด ์๋ค. ์ด๋ฆ์ด flag.enc ๋ผ๋ ๊ฒ,
๊ทธ๋ฆฌ๊ณ ํ์ฅ์๊ฐ .enc ๋ผ๋ ๊ฒ๋ง ๋ถ๋ค๊ณ ์์ํ๋ค.
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Run (2022 Spring GoN Open Qual CTF ์ถ์ ์) |
| ๋์ด๋ | ๐ Platinum 4 |
| ๋ถ๋ฅ | reversing |
| ์ ๊ณต ํ์ผ | main (10,216 B ยท stripped PIE ELF64) ยท flag.enc (160,672 B) |
| ์๋ฒ | ์์ (์คํ๋ผ์ธ ๋ฌธ์ ) |
| ์คํ | C ยท glibc ์ ์์ค ์
์ถ๋ ฅ(open/read/lseek/write)๋ง ์ฌ์ฉ |
| ํต์ฌ ๊ธฐ๋ฒ | 0 ์ ๋ฐ๋ ์ค๋ฅผ Elias ๊ฐ๋ง ์ ์ฌ ์ฝ๋๋ก ์ธ์ฝ๋ฉ, ๋ฐ์ดํธ ์์์ LSB-first |
ํ์ด ํ๋ฆ์ ์งง๋ค. main ์ ๋ณตํธ๊ธฐ๊ฐ ์๋๋ผ ์ธ์ฝ๋๋ค. ์ธ์๋ก ๋ฐ์ ํ์ผ์ ํต์งธ๋ก ์ฝ์ด
<ํ์ผ์ด๋ฆ>.enc ๋ฅผ ๋ฑ๋๋ค. ๊ทธ๋ฌ๋ flag.enc ๋ flag ๋ผ๋ ํ์ผ์ ์ด ํ๋ก๊ทธ๋จ์ ํ ๋ฒ ํต๊ณผ์ํจ
๊ฒฐ๊ณผ๋ฌผ์ด๊ณ , ์ฐ๋ฆฌ๊ฐ ํ ์ผ์ ์ด ์ธ์ฝ๋๋ฅผ ์ ํํ ์ฝ์ด ์ญํจ์๋ฅผ ์ฐ๋ ๊ฒ์ด๋ค.
ํจ์ ์ ๋ฑ ํ๋๋ค. ๋ฐ์ ๋์์ด 1 ์ด ์๋๋ผ 0 ์ด๋ผ๋ ๊ฒ. ์ด ์กฐ๊ฑด ๋ถ๊ธฐ ํ ์ค์ ๋ฐ๋๋ก ์ฝ์ผ๋ฉด ๋ณต์์ ๋๊น์ง ๋ฉ์ฉกํ๊ฒ ๋๋ฉด์ ๊ฒฐ๊ณผ๋ง ์ ๋นํธ ๋ฐ์ ๋ณธ์ด ๋๋ค.
๐งฉ ์ ์ฐฐ โ ์ฌ๋ณผ๋ ๋ฌธ์์ด๋ ์๋ 10KB
stripped ๋ผ nm ์ ์๋ฌด๊ฒ๋ ๋ชป ์ค๋ค. ๋์ ๋์ ์ฌ๋ณผ ํ
์ด๋ธ์ ๋จ์ ์๊ณ , ์ฌ๊ธฐ๊ฐ ์ ์ผ ๋ง์ ๊ฑธ ๋งํด ์ค๋ค.
readelf --dyn-syms -W extracted/main
๊ฐ์ ธ๋ค ์ฐ๋ libc ํจ์๊ฐ ์ด ๋ช ๊ฐ๋ฟ์ด๊ณ , ๊ทธ ์กฐํฉ์ด ๋
ธ๊ณจ์ ์ด๋ค.
open ยท lseek ยท read ยท write ยท close ๋ก ํ์ผ์ ์ง์ ๋ค๋ฃจ๊ณ ,
malloc ยท realloc ยท free ๋ก ๋ฒํผ๋ฅผ ๋๋ ธ๋ค ์ค์ด๊ณ , sprintf ์ strlen ์ผ๋ก ๋ฌธ์์ด์ ํ๋ ๋ง๋ ๋ค.
fopen ๋ printf ๋ ์๋ค. ํ๋ฉด์ ๋ญ ์ถ๋ ฅํ๋ ํ๋ก๊ทธ๋จ์ด ์๋๋ผ๋ ๋ป์ด๋ค.
๋ฌธ์์ด ์ชฝ์ ๋ ์์ํ๋ค.
strings -a extracted/main | wc -l; strings -a extracted/main | grep -nE "enc|flag|GoN|%"
51์ค์ด ๋์ค๋๋ฐ ๋๋ถ๋ถ ์น์
์ด๋ฆ์ด๊ณ , ์ฌ๋์ด ์ด ๋ฌธ์์ด์ %s.enc ํ๋๋ค.
sprintf ์ ํฌ๋งท ๋ฌธ์์ด์ด ๊ทธ๊ฒ ํ๋๋ผ๋ ๋ป์ด๊ณ , ๊ทธ๋ ๋ค๋ฉด ๋ง๋ค์ด ๋ด๋ ํ์ผ ์ด๋ฆ์
์
๋ ฅํ์ผ์ด๋ฆ + .enc ๋ค. flag.enc ๋ผ๋ ๋ฐฐํฌ ํ์ผ ์ด๋ฆ์ด ๊ณง "์๋ณธ์ flag ์๋ค" ๋ ์ฆ๊ฑฐ๊ฐ ๋๋ค.
ํ๋๊ทธ ๋ฌธ์์ด ์์ฒด๋ ๋ฐ์ด๋๋ฆฌ ์ด๋์๋ ์๋ค. ์ด ๋ฌธ์ ๋ ๊ฒ์ฆ๊ธฐ๊ฐ ์๋๋ผ ๋ณํ๊ธฐ๋ค.
๐ฌ main() โ ํ์ผ์ ํต์งธ๋ก ๋นํธ์คํธ๋ฆผ์ ์น๋๋ค
.text ๋ 0x870 ๋ถํฐ 0xf82 ๊น์ง, 1810๋ฐ์ดํธ๋ค. ํจ์๋ ์ฌ๋ ๊ฐ๊ณ ๊ทธ์ค ์ ๋ฐ์ด ๋นํธ ํ๋๋ฅผ
์ฝ๊ณ ์ฐ๋ ๋์ฐ๋ฏธ๋ค. ์ํธ๋ฆฌ์์ __libc_start_main ์ ๋๊ธฐ๋ ์ฒซ ์ธ์๊ฐ 0xd87 ์ด๋ผ ๊ฑฐ๊ธฐ๊ฐ main ์ด๋ค.
์๋ถ๋ถ์ ํ์ผ์ ์ฌ๋ ๊ณณ์ด๋ค. ์ฃผ์์ ๋ด๊ฐ sed ๋ก ์น์ ๊ฒ์ด๊ณ , ๋๋จธ์ง๋ objdump ์๋ฌธ ๊ทธ๋๋ก๋ค.
objdump -d -M intel --no-show-raw-insn --start-address=0xda5 --stop-address=0xe24 extracted/main | sed -f annot_main.sed![ํด๋ฆญํ์ฌ ํ๋ objdump ๋ก ๋ณธ main ์๋ถ๋ถ โ argc ๋ฅผ 2์ ๋น๊ตํ๊ณ open ์ผ๋ก argv[1] ์ ์ฐ ๋ค 0xb8f ์ read_file ๋ก ํต์งธ๋ก ์ฝ๊ณ 0xb2c ์ bs_init ์ผ๋ก ์ถ๋ ฅ ๋ฒํผ๋ฅผ 4096๋ฐ์ดํธ ์ก์ ๋ค์ 0xc60 ์ encode ๋ฅผ ํธ์ถํ๋ค](/_next/image?url=%2Fimages%2Fblog%2Fdreamhack-run-writeup%2F04_objdump_main.png&w=3840&q=75)
์ธ์ ๊ฐ์๋ฅผ 2 ๋ก ๋ชป ๋ฐ๊ณ , argv[1] ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ฐ๋ค. ๊ทธ ๋ค์์ด ์ด ๋ฌธ์ ์ ๊ณจ๊ฒฉ์ด๋ค.
read_file(&src, fd) ๋ก ํ์ผ ์ ์ฒด๋ฅผ ํ๋์ ๋นํธ์คํธ๋ฆผ์ ๋ด๊ณ ,
bs_init(&dst, 0x1000) ์ผ๋ก ์ถ๋ ฅ์ฉ ๋นํธ์คํธ๋ฆผ์ 4KB ๋ก ์ก๊ณ ,
encode(&src, &dst) ๋ฅผ ๋ถ๋ฅธ๋ค.
๋ท๋ถ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ฐ๋ ๊ณณ์ด๋ค.
objdump -d -M intel --no-show-raw-insn --start-address=0xe58 --stop-address=0xee5 extracted/main | sed -f annot_main.sed
0xead ์ lea rcx,[rax+0x10] ๊ณผ ๊ทธ ๋ค์ write(fd, rcx, 8) ์ด ์ค์ํ๋ค.
rax ๋ src ๊ตฌ์กฐ์ฒด์ ์ฃผ์๊ณ , ๊ฑฐ๊ธฐ์ 0x10 ์ ๋ํ ์๋ฆฌ์์ 8๋ฐ์ดํธ๋ฅผ ๊ทธ๋๋ก ์ด๋ค.
์ถ๋ ฅ ํ์ผ์ ์ฒซ 8๋ฐ์ดํธ๋ ์ธ์ฝ๋ฉ ๊ฒฐ๊ณผ๊ฐ ์๋๋ผ src ๊ตฌ์กฐ์ฒด์ ์ธ ๋ฒ์งธ ํ๋๋ผ๋ ๋ป์ด๋ค.
๊ทธ๊ฒ ๋ญ์ง๋ ๊ณง ๋์จ๋ค.
์ ์ฒด๋ฅผ C ๋ก ์ฎ๊ธฐ๋ฉด ์ด๋ ๋ค.
int main(int argc, char **argv) {
BitStream src, dst;
if (argc != 2) exit(1);
int fd = open(argv[1], O_RDONLY);
if (fd == -1) exit(1);
read_file(&src, fd); /* ํ์ผ ์ ์ฒด -> src */
close(fd);
bs_init(&dst, 0x1000); /* ์ถ๋ ฅ ๋ฒํผ 4KB ๋ก ์์ */
encode(&src, &dst);
char *path = malloc(strlen(argv[1]) + 5); /* ".enc" + NUL */
if (!path) exit(1);
sprintf(path, "%s.enc", argv[1]);
fd = open(path, O_CREAT | O_WRONLY, 0600);
if (fd == -1) exit(1);
write(fd, &src.cap, 8); /* ํค๋ 8๋ฐ์ดํธ */
flush(&dst, fd); /* ์ธ์ฝ๋ฉ ๋ณธ๋ฌธ */
close(fd);
free(path);
return 0;
}๐งฑ ๋นํธ์คํธ๋ฆผ โ ๊ตฌ์กฐ์ฒด ํ๋์ ๋์ฐ๋ฏธ ๋ค์ฏ
0x97a ยท 0xaad ยท 0xb2c ยท 0xb8f ยท 0xc08 ๋ค์ฏ ํจ์๊ฐ ์ ๋ถ ๊ฐ์ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง์ง๋ค. ์คํ์ 0 ์ ํฌ์ธํฐ, 8 ์ ํ๋, 0x10 ์ ํ๋. ์ฐ์์๋ฅผ ๋ณด๋ฉด ์ ์ฒด๊ฐ ๋ฐ๋ก ๋์จ๋ค.
typedef struct {
char *buf; /* +0x00 */
size_t pos; /* +0x08 ํ์ฌ ์์น โ ๋ฐ์ดํธ๊ฐ ์๋๋ผ ๋นํธ ๋จ์ */
size_t cap; /* +0x10 ์ฉ๋ โ ์ญ์ ๋นํธ ๋จ์ */
} BitStream;pos ๋ฅผ ์ธ ๋๋ง๋ค shr rax,0x3 ๋ก 8 ์ ๋๋ ๋ฒํผ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค๊ณ and edx,0x7 ๋ก ๋๋จธ์ง๋ฅผ
๋นํธ ์์น๋ก ์ด๋ค. ๊ทธ๋์ ๋ ๋ค ๋นํธ ๋จ์๋ค. ๋์ฐ๋ฏธ ๋ค์ฏ์ ์ด๋ ๊ฒ ๋์ํ๋ค.
void bs_init(BitStream *bs, size_t n) { /* 0xb2c */
if (n > 0x1fffffffffffffff) exit(1);
bs->buf = malloc(n);
bs->cap = n * 8; /* n ๋ฐ์ดํธ = n*8 ๋นํธ */
bs->pos = 0;
}
void read_file(BitStream *bs, int fd) { /* 0xb8f */
size_t sz = lseek(fd, 0, SEEK_END);
bs_init(bs, sz);
lseek(fd, 0, SEEK_SET);
if (read(fd, bs->buf, sz) != sz) exit(1);
}
void put_bit(BitStream *bs, int b) { /* 0x97a */
if (bs->pos >= bs->cap) {
bs->cap *= 2;
bs->buf = realloc(bs->buf, bs->cap); /* ๋นํธ ์๋ฅผ ๋ฐ์ดํธ ์๋ก ๋๊ธด๋ค */
if (!bs->buf) exit(1);
}
bs->buf[bs->pos >> 3] &= ~(1 << (bs->pos & 7));
bs->buf[bs->pos >> 3] |= (b != 0) << (bs->pos & 7);
bs->pos++;
}
int get_bit(BitStream *bs) { /* 0xaad */
if (bs->pos >= bs->cap) exit(1);
return (bs->buf[bs->pos >> 3] >> (bs->pos++ & 7)) & 1;
}
void flush(BitStream *bs, int fd) { /* 0xc08 */
while (bs->pos & 7) put_bit(bs, 1); /* ๋จ๋ ์๋ฆฌ๋ 1 ๋ก ์ฑ์ด๋ค */
write(fd, bs->buf, bs->pos >> 3);
}์ฌ๊ธฐ์ ์ญํจ์์ ํ์ํ ๊ท์น ๋ ๊ฐ๊ฐ ํ์ ๋๋ค.
๋นํธ ์์๋ ๋ฐ์ดํธ ์์์ LSB-first๋ค. 1 << (pos & 7) ์ด๋ผ pos ๊ฐ 0 ์ผ ๋ ์ตํ์ ๋นํธ๋ฅผ
๊ฑด๋๋ฆฐ๋ค. ํํ ์ฐ๋ MSB-first ๋ก ์ฝ์ผ๋ฉด ์ฒซ ์ฝ๋์๋๋ถํฐ ์ด๊ธ๋๋ค.
๊ผฌ๋ฆฌ ํจ๋ฉ์ 1 ์ด๋ค. flush ๊ฐ ๋ฐ์ดํธ ๊ฒฝ๊ณ๋ฅผ ๋ง์ถ๋ ค๊ณ ์ฑ์ฐ๋ ๊ฐ์ด 1 ์ด๋ผ, ๋์ฝ๋๊ฐ ํ์ผ ๋์์
์ฐ๋ ๊ธฐ ์ฝ๋์๋๋ฅผ ๋ช ๊ฐ ๋ ์ฝ์ ์ ์๋ค. ์๋ณธ ๊ธธ์ด๋ฅผ ์๊ณ ๊ฑฐ๊ธฐ์ ๋์ด์ผ ํ๋ ์ด์ ๋ค.
put_bit ์ realloc(bs->buf, bs->cap) ์ ๋นํธ ์๋ฅผ ๋ฐ์ดํธ ์ ์๋ฆฌ์ ๋๊ธฐ๋ ์ฝ๋๋ค.
8๋ฐฐ๋ก ๋๋ํ ์กํ๋ ๋์์๋ ๋ฌธ์ ๊ฐ ์๊ณ , ์ธ์ฝ๋๊ฐ ์์ผ๋ก ์ด ์ฝ๋๋ผ๋ ํ์ ์ ๋๋ก ๋ณด๋ฉด ๋๋ค.
๐ฃ ํต์ฌ โ encode() ๊ฐ ์ธ๋ ๊ฒ์ 1 ์ด ์๋๋ผ 0 ์ด๋ค
์ด์ 0xc60 ์ด๋ค. ์ด ํจ์๋ง ์ ํํ ์ฝ์ผ๋ฉด ๋ฌธ์ ๊ฐ ๋๋๋ค.
objdump -d -M intel --no-show-raw-insn --start-address=0xc60 --stop-address=0xcdb extracted/main | sed -f annot_encode.sed
0xca4 ์์ get_bit(src) ๋ฅผ ๋ถ๋ฅธ๋ค. ๊ทธ ๋ค์ ๋ ์ค์ด ์ด ๋ฌธ์ ์ ์ ๋ถ๋ค.
ca9: test eax,eax ; ๋ฐฉ๊ธ ์ฝ์ ๋นํธ
cab: je c7f ; 0 ์ด๋ฉด c7f ๋ก -- c7f ๋ count++ ํ๋ ์๋ฆฌ๋คje ๋ "๊ฐ์ผ๋ฉด" ์ด๊ณ ๋น๊ต ๋์์ 0 ์ด๋ค. ์ฆ ์ฝ์ ๋นํธ๊ฐ 0 ์ผ ๋ ์ธ๋ฌ ๊ฐ๋ค.
jne ์๋ค๋ฉด 1 ์ ์ธ๋ ๊ฒ์ด๊ณ , ๊ธ์ ํ๋ ์ฐจ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ํ ๊ธ์๊ฐ ๋ณต์๋ณธ ์ ์ฒด์ ๊ทน์ฑ์ ๋ค์ง๋๋ค.
0xc7f ๋ count++ ํ๊ธฐ ์ ์ src->pos < src->cap ์ ํ ๋ฒ ๋ ๋ณธ๋ค. 0 ์ ์ฝ์๋๋ฐ ์คํธ๋ฆผ์ด
๋ฐ๋ฅ๋๋ฉด ๊ทธ ๋ฐ์ ํต์งธ๋ก ๋ฒ๋ฆฌ๊ณ ํจ์๊ฐ ๋๋๋ค. ํ์ผ ๋งจ ๋์ ์๋ฆฐ ๋ฐ์ ์ถ๋ ฅ์ ์ ์ค๋ฆฐ๋ค๋ ๋ป์ด๋ค.
count ๊ฐ ์ ํด์ง๋ฉด ๋ท๋ถ๋ถ์ด ๊ทธ๊ฑธ ๋นํธ๋ก ํธ๋ค.
objdump -d -M intel --no-show-raw-insn --start-address=0xcdb --stop-address=0xd6a extracted/main | sed -f annot_encode.sed
bsr rax, count ๊ฐ ์ต์์ 1 ๋นํธ์ ์์น๋ฅผ ์ฃผ๊ณ , xor rax, 0x3f ๊ฐ ๊ทธ๊ฑธ 63 ์์ ๋นผ์ clz ๋ก ๋ฐ๊พผ๋ค.
0x40 - clz ๋ ๊ณง count ์ ๋นํธ๊ธธ์ด๋ค. ์ปดํ์ผ๋ฌ๊ฐ __builtin_clzll ์ ํธ ๋ชจ์ ๊ทธ๋๋ก๋ค.
void encode(BitStream *src, BitStream *dst) {
while (src->pos < src->cap) {
size_t count = 0;
while (get_bit(src) == 0) { /* 0 ์ ์ผ๋ค */
if (src->pos >= src->cap) return;
count++;
}
if (count == 0) { put_bit(dst, 0); put_bit(dst, 0); continue; }
size_t nbits = 64 - __builtin_clzll(count); /* count ์ ๋นํธ๊ธธ์ด */
for (int i = 0; i < nbits - 1; i++) put_bit(dst, 1);
put_bit(dst, 0);
for (int j = 0; j < nbits; j++) { put_bit(dst, count & 1); count >>= 1; }
}
}์๋ณธ ๋นํธ์ด์ "0 ์ด ๋ช ๊ฐ ์ด์ด์ง๋ค 1 ๋ก ๋๋๋ ๋ฐ" ์ ๋์ด๋ก ๋ณด๊ณ , ๊ทธ ๋ฐ์ ๊ธธ์ด๋ง ์ ๋ ๊ตฌ์กฐ๋ค.
๊ธธ์ด๋ฅผ ์ ๋ ๋ฐฉ์์ Elias ๊ฐ๋ง ์ฝ๋์ ๊ฐ์ ๊ผด์ด๋ค. ์์ 1 ์ nbits-1 ๊ฐ ๋ถ์ฌ ๊ธธ์ด๋ฅผ ์๋ฆฌ๊ณ ,
0 ํ๋๋ก ๋๊ณ , ๊ฐ์ nbits ๋นํธ๋ก ์ ๋๋ค. ๋ค๋ง ๊ฐ ๋ถ๋ถ์ด ๊ต๊ณผ์์ฒ๋ผ MSB-first ๊ฐ ์๋๋ผ
LSB-first ๋ค. put_bit(dst, count & 1) ๋ค์์ count >>= 1 ์ด๋ ์ตํ์ ๋นํธ๊ฐ ๋จผ์ ๋๊ฐ๋ค.

count == 0 ์ ํน์ ์ผ์ด์ค์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ท์น์ด ๊ฐ๋ค. nbits ๊ฐ 1 ์ด๋ผ ์ ๋๋ฆฌ ๋ถ๋ถ์ด ๋น๊ณ
๊ฐ ๋นํธ ํ๋(0)๋ง ๋จ์์ 0 0 ๋ ๋นํธ๊ฐ ๋๋ค. ๋์ฝ๋์์ ๋ฐ๋ก ๋ถ๊ธฐํ ํ์๊ฐ ์๋ค.
๋์ฝ๋ ์ ์ฅ์์ ์ ๋ฆฌํ๋ฉด ์ด๋ ๋ค.
| ์ฝ๋ ์์ | ํ๋ ์ผ |
|---|---|
| 1 | 0 ์ ๋ง๋ ๋๊น์ง 1 ์ ์ผ๋ค. ์ผ ๊ฐ์๋ฅผ k ๋ผ ํ๋ฉด nbits = k + 1 |
| 2 | ๊ทธ ๋ค๋ก nbits ๋นํธ๋ฅผ LSB-first ๋ก ์ฝ์ด count ๋ฅผ ๋ง๋ ๋ค |
| 3 | 0 ์ count ๊ฐ, ๊ทธ๋ฆฌ๊ณ 1 ์ ํ๋ ๋ฑ๋๋ค |
| 4 | ์๋ณธ ๋นํธ ์๋ฅผ ์ฑ์ธ ๋๊น์ง ๋ฐ๋ณต |
๐งช ์ ์ ๋ถ์์ ๋ฐํ์์ผ๋ก ๋ชป ๋ฐ๊ธฐ
์ฝ์ ๊ฒ ๋ง๋์ง ์ค์ ๋ก ๋๋ ค์ ํ์ธํ๋ค. PIE ๋ผ ์ฃผ์๊ฐ ๋งค๋ฒ ๋ฌ๋ผ์ง๋๋ฐ, ์ฌ๊ธฐ์ ๋ฒ ์ด์ค๋ฅผ
๊ด๋ก๋ก ๊ฐ์ ํ๋ฉด ์ ๋๋ค. info proc mappings ์์ ์ค์ ๋งคํ์ ์ฝ์ด ์ด๋ค.
set confirm off
set pagination off
starti
python
import gdb
base = None
for line in gdb.execute("info proc mappings", to_string=True).splitlines():
if line.rstrip().endswith("/main"): # PIE ๋ฒ ์ด์ค๋ ๊ฐ์ ํ์ง ์๊ณ ๋งคํ์์ ์ฝ๋๋ค
base = int(line.split()[0], 16)
break
gdb.execute("set $base = %#x" % base)
print("PIE base = %#x" % base)
end
break *($base + 0xc60)
break *($base + 0xcdb)
continue
printf "encode(src=%p, dst=%p)\n", $rdi, $rsi
printf " src->buf = %p\n", *(long *)$rdi
printf " src->pos = %ld\n", *(long *)($rdi + 8)
printf " src->cap = %ld bits = %ld B\n", *(long *)($rdi + 16), *(long *)($rdi + 16) / 8
printf " src->buf[0..3] = %02x %02x %02x %02x\n", *(unsigned char *)(*(long *)$rdi), *(unsigned char *)(*(long *)$rdi + 1), *(unsigned char *)(*(long *)$rdi + 2), *(unsigned char *)(*(long *)$rdi + 3)
continue
printf "count != 0 ์ธ ์ฒซ ์ฝ๋์๋ (0xcdb)\n"
printf " count = %ld\n", *(long *)($rbp - 0x10)
printf " src->pos = %ld (์๋นํ ์๋ณธ ๋นํธ)\n", *(long *)(*(long *)($rbp - 0x28) + 8)
printf " dst->pos = %ld (๋ฑ์ ์ถ๋ ฅ ๋นํธ)\n", *(long *)(*(long *)($rbp - 0x30) + 8)
killgdb -q -batch -x cmds.gdb --args extracted/main flag.png
์ธ ๊ฐ์ง๊ฐ ํ ๋ฒ์ ํ์ธ๋๋ค.
src->cap ์ด 3,928,984 ๋นํธ, ๋๋๋ฉด 491,123 ๋ฐ์ดํธ๋ค. ๊ตฌ์กฐ์ฒด ์ธ ๋ฒ์งธ ํ๋๊ฐ ์๋ณธ ํ์ผ ํฌ๊ธฐ๋ผ๋
์ถ๋ก ์ด ๋ง์๋ค. ๊ทธ๋ฆฌ๊ณ main ์ด ์ถ๋ ฅ ํ์ผ ๋งจ ์์ ์ฐ๋ 8๋ฐ์ดํธ๊ฐ ๋ฐ๋ก ์ด ๊ฐ์ด๋ค.
src->buf[0..3] ์ด 89 50 4e 47 ์ด๋ค. ์๋ณธ์ด PNG ์๋ค๋ ์ฌ์ค์ด ์ธ์ฝ๋ฉ ์ ๋จ๊ณ์์ ์ด๋ฏธ ๋๋ฌ๋๋ค.
๋ณต์ ๊ฒฐ๊ณผ๊ฐ PNG ๊ฐ ์๋๋ฉด ๋ด๊ฐ ํ๋ฆฐ ๊ฒ์ด๋ผ๋ ๊ธฐ์ค์ ์ด ์ฌ๊ธฐ์ ์๊ธด๋ค.
์ฒซ ์ฝ๋์๋์์ count = 2, src->pos = 4, dst->pos = 2 ๋ค. ์์ผ๋ก ๋ง์ถฐ ๋ณด๋ฉด
0x89 ๋ LSB-first ๋ก 1 0 0 1 0 0 0 1 ์ด๋ค. ์ฒซ ๋นํธ๊ฐ 1 ์ด๋ผ ์ฒซ ๋ฐ์ count = 0 ์ด๊ณ 0 0
๋ ๋นํธ๊ฐ ๋๊ฐ๋ค(dst->pos = 2). ๊ทธ ๋ค์ 0 ์ ๋ ๊ฐ ์ธ๊ณ 1 ์ ๋ง๋ ๋ฉ์ถ๋ count = 2,
src->pos = 4. ์ซ์๊ฐ ๊ทธ๋๋ก ๋ง๋๋ค.
๐ ํค๋ 8๋ฐ์ดํธ๋ถํฐ ์ฝ์ด ๋ณธ๋ค
๋ฐ์ด๋๋ฆฌ ์ชฝ ๋ถ์์ด ๋๋ฌ์ผ๋ ์ด์ flag.enc ๋ฅผ ์ง์ ๋ณธ๋ค.
#!/usr/bin/env python3
"""flag.enc ์ 8๋ฐ์ดํธ(= ์ธ์ฝ๋๊ฐ ์จ ๋ฃ์ src->cap)๋ฅผ ์ฝ์ด ์๋ณธ ํฌ๊ธฐ๋ฅผ ์ญ์ฐํ๋ค."""
import sys
blob = open(sys.argv[1], 'rb').read()
n_bits = int.from_bytes(blob[:8], 'little')
print(f'ํ์ผ ์ ์ฒด : {len(blob)} B')
print(f'ํค๋ 8๋ฐ์ดํธ : {blob[:8].hex(" ")}')
print(f'-> src->cap : {n_bits} bits = {n_bits // 8} B (์๋ณธ ํ์ผ ํฌ๊ธฐ)')
print(f'์ธ์ฝ๋ฉ ๋ณธ๋ฌธ : {len(blob) - 8} B')
print(f'๋น์จ : {(len(blob) - 8) / (n_bits // 8):.3f} ๋ฐฐ (๋์ด๋ ๊ฒ ์๋๋ผ ์ค์๋ค)')
print(f'๋ณธ๋ฌธ ์ฒซ 4๋ฐ์ดํธ: {blob[8:12].hex(" ")}')
bits = ''.join(f'{blob[8 + i]:08b}'[::-1] for i in range(3)) # ๋ฐ์ดํธ ์์์ LSB-first
print(f'-> ๋นํธ์ด(LSB-first) : {bits}')python3 read_header.py extracted/flag.enc
ํค๋๊ฐ gdb ๋ก ๋ณธ src->cap ๊ณผ ์ ํํ ๊ฐ๋ค. ์๋ณธ์ 491,123 ๋ฐ์ดํธ๋ค.
๋์ ๋๋ ๊ฑด ํฌ๊ธฐ๋ค. ์ธ์ฝ๋ฉ ๋ณธ๋ฌธ์ด 160,664 ๋ฐ์ดํธ๋ผ ์๋ณธ์ 0.327 ๋ฐฐ๋ค. ๋ฐ๋ ์ค ์ธ์ฝ๋ฉ์ ๋ณดํต ๋๋คํ ๋ฐ์ดํฐ๋ฅผ ๋ง๋๋ฉด ๋ ๋ฐฐ ๊ฐ๊น์ด ๋ถํ์ด ์ค๋ฅด๋๋ฐ, ์ฌ๊ธฐ์๋ 3๋ถ์ 1 ๋ก ์ค์๋ค. 0 ์ด ๊ธธ๊ฒ ์ด์ด์ง๋ ๊ตฌ๊ฐ์ด ์์ฃผ ๋ง๋ค๋ ๋ป์ด๊ณ , ํฐ ๋จ์ ์์ญ์ ๊ฐ์ง ๊ทธ๋ฆผ์ด๋ผ๋ ํํธ๋ค.
๋ณธ๋ฌธ ์ฒซ ์ธ ๋ฐ์ดํธ๋ฅผ LSB-first ๋ก ํด๋ฉด 001001101111000101100100 ์ด๋ค. ์์ผ๋ก ์ธ ์ฝ๋์๋๋ง ์ฝ์ด ๋ณด์.
| ์ฝ์ ๋นํธ | ํด์ | ๋ฑ๋ ์๋ณธ ๋นํธ |
|---|---|---|
0 0 | k=0 ์ด๋ผ nbits=1, ๊ฐ 0 โ count=0 | 1 |
10 01 | k=1 ์ด๋ผ nbits=2, LSB-first ๋ก 0ยท1 โ count=2 | 001 |
10 11 | k=1 ์ด๋ผ nbits=2, LSB-first ๋ก 1ยท1 โ count=3 | 0001 |
์ด์ด ๋ถ์ด๋ฉด 1 0 0 1 0 0 0 1 ์ด๊ณ , LSB-first ๋ก ํ ๋ฐ์ดํธ๋ฅผ ๋ง๋ค๋ฉด 0x89 ๋ค. PNG ๋งค์ง ์ฒซ ๋ฐ์ดํธ๊ฐ
์์ผ๋ก ๊ณ์ฐํด์ ๋์๋ค. ์ด์ ์ฝ๋๋ก ์ฎ๊ธฐ๋ฉด ๋๋ค.
๐ ์ฌ๊ธฐ์ ํ ๋ฒ ํฌ๊ฒ ํค๋งธ๋ค
โถ๐ ์ฝ์ง โ 1 ์ ์ธ๋ ์ค ์๊ณ ์ง ๋์ฝ๋, ๊ฒฐ๊ณผ๊ฐ ํต์งธ๋ก ๋นํธ ๋ฐ์ ๋๋ค
์ฒ์ ๋์ฝ๋๋ฅผ ์งค ๋ test eax,eax ๋ค์์ je ๋ฅผ ๋์ถฉ "๋นํธ๊ฐ 1 ์ด๋ฉด ์ผ๋ค" ๋ก ์ฝ๊ณ ๋์ด๊ฐ๋ค.
์ด์
๋ธ๋ฆฌ๋ฅผ ์ฝ๋ค ๋ณด๋ฉด ์กฐ๊ฑด์ด ๋ค์งํ ์ชฝ์ด ์คํ๋ ค ์์ฐ์ค๋ฌ์ ๋ณด์ผ ๋๊ฐ ์๋๋ฐ ์ฌ๊ธฐ๊ฐ ๊ทธ๋ฌ๋ค.
๊ทธ๋์ ๋ง๋ ๊ฒ ์๋ ๋์ฝ๋๋ค. ๋ฐ์ ๋์๋ง 1 ๋ก ๋ฐ๊ฟจ์ ๋ฟ ๋๋จธ์ง๋ ์ต์ข ๋ณธ๊ณผ ๊ฐ๋ค.
#!/usr/bin/env python3
"""์ฝ์ง ๊ธฐ๋ก โ encode() ์ `test eax,eax; je` ๋ฅผ '1 ์ด๋ฉด ์ผ๋ค'๋ก ์๋ชป ์ฝ์์ ๋์ ๋์ฝ๋.
๋ฐ์ ๋์์ 1 ๋ก ๋๋ฉด ๋ณต์๋ณธ์ด ์ ๋ต์ ์ ๋นํธ ๋ฐ์ ๋ณธ์ด ๋๋ค.
๊ฒฐ๊ณผ๊ฐ '๋ฐ์ดํฐ'๋ก๋ง ๋ณด์ฌ์ ํ์ฐธ์ ๋ด ๋ฐ์ ์์ธ์ ์ฐพ์๋ค.
"""
import sys
from decode import BitReader
def decode_ones(blob):
n_bits = int.from_bytes(blob[:8], 'little')
br = BitReader(blob[8:])
out = bytearray((n_bits + 7) // 8)
pos = 0
while pos < n_bits:
try:
k = 0
while br.bit():
k += 1
count = 0
for j in range(k + 1):
count |= br.bit() << j
except EOFError:
break
for _ in range(count): # โ ์ฌ๊ธฐ๊ฐ ํ๋ ธ๋ค: 1 ์ count ๊ฐ ์ฑ์ด๋ค
if pos >= n_bits:
break
out[pos >> 3] |= 1 << (pos & 7)
pos += 1
pos += 1 # ๋ฐ์ ๋๋ด๋ 0 (๊ทธ๋ฅ ๊ฑด๋๋ด๋ค)
return bytes(out[:n_bits // 8])
if __name__ == '__main__':
res = decode_ones(open(sys.argv[1], 'rb').read())
print(f'๋ณต์ {len(res)}B, ์ 16๋ฐ์ดํธ = {res[:16].hex(" ")}')
print(f'ASCII = {res[:16]!r}')
print(f'PNG ๋งค์ง์ธ๊ฐ? {res[:4] == b"\\x89PNG"}')
print(f'๊ฐ ๋ฐ์ดํธ๋ฅผ ๋ฐ์ ํ๋ฉด {bytes(b ^ 0xff for b in res[:8])!r} <- ์ ๋ต์ด ์ฌ๊ธฐ ์์๋ค')python3 decode_wrong.py extracted/flag.enc
๋ฌธ์ ๋ ์ด๊ฒ ๊น๋ํ๊ฒ ์คํจํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค. ๋ณต์ ๋นํธ ์๋ 3,928,984 / 3,928,984 ๋ก ๋๊น์ง ๋ฑ ๋ง๊ณ , ํฌ๊ธฐ๋ ํค๋๊ฐ ๋งํ 491,123 ๋ฐ์ดํธ๊ฐ ๊ทธ๋๋ก ๋์จ๋ค. ์ฝ๋์๋ ๋ฌธ๋ฒ ์์ฒด๋ ๋ง๊ฒ ์ฝ๊ณ ์์ผ๋ ์ค๊ฐ์ ์ด๊ธ๋ ๋ฐ๊ฐ ์๋ค. ๋ค๋ง ๋ฑ๋ ๊ฐ์ด ์ ๋ถ ๋ฐ๋์ผ ๋ฟ์ด๋ค.
file ์ ๊ฒฐ๊ณผ๋ฌผ์ ๊ทธ๋ฅ data ๋ผ๊ณ ํ๊ณ , ๋๋ ํค๋ ํ์ฑ์ด๋ ๋นํธ ์์๋ฅผ ํ์ฐธ ์์ฌํ๋ค.
์ 16๋ฐ์ดํธ๊ฐ 76 af b1 b8 f2 f5 e5 f5 ff ff ff f2 โฆ ์ธ๋ฐ ff ๊ฐ ์๋ฉ ๋ณด์ด๋ ๊ฒ ์ด์ํด์
๋ฐ์ ํด ๋ดค๋๋ 89 50 4e 47, PNG ์๋ค.
์ ๋นํธ๊ฐ ๋ฐ์ ๋๋ค๋ ๊ฑด 0 ๊ณผ 1 ์ ์ญํ ๋ง ๋ฐ๋์๋ค๋ ๋ป์ด๊ณ , ๊ทธ๋ผ ์์ธ์ ๋ฐ์ ๋์ ํ๋๋ฟ์ด๋ค.
objdump ๋ก ๋์๊ฐ cab: je c7f ๋ฅผ ๋ค์ ๋ณด๋ ์ ํ ๋์ 0xc7f ๊ฐ count++ ํ๋ ์๋ฆฌ์๋ค.
je ๋๊น 0 ์ผ ๋ ๋ด๋ค. ์ธ๋ ๊ฑด 0 ์ด์๋ค.
"๋ณต์์ด ๋๊น์ง ๋์๋ค" ๋ ๊ฒ ์์ฒด๋ ์๋ฌด ๋ณด์ฆ๋ ์๋๋ค. ์ด ๋ฌธ์ ์ฒ๋ผ ์ฝ๋์๋ ๋ฌธ๋ฒ๊ณผ ๊ฐ ํด์์ด ๋ถ๋ฆฌ๋ผ ์์ผ๋ฉด, ๊ฐ์ ํต์งธ๋ก ํ๋ ค๋ ๊ธธ์ด ๊ณ์ฐ์ ์๋ฒฝํ๊ฒ ๋ง์๋จ์ด์ง๋ค. ํฌ๋งท์ ๋๊ฐ์ ๋๋ ๊ธธ์ด๊ฐ ์๋๋ผ ๋งค์ง ๋๋ฒ ๊ฐ์ ๋ ๋ฆฝ ์งํ๋ก ํ์ ํด์ผ ํ๋ค.
๐ฏ ๋์ฝ๋
์ญํจ์๋ ์งง๋ค. ํค๋์์ ์๋ณธ ๋นํธ ์๋ฅผ ์ฝ๊ณ , ์ฝ๋์๋๋ฅผ ํ๋์ฉ ํ์ด 0 ์ count ๊ฐ, 1 ์ ํ๋์ฉ
์ฑ์ฐ๋ฉด ๋๋ค. ์ถ๋ ฅ ๋ฒํผ๋ฅผ 0 ์ผ๋ก ์์ํ๋ฉด 0 ์ ๊ทธ๋ฅ ๊ฑด๋๋ฐ๊ณ 1 ๋ง ์ธ์๋ ๋๋ค.
#!/usr/bin/env python3
"""main ๋ฐ์ด๋๋ฆฌ(0-๋ฐ๋ ์ค + Elias-gamma ์ธ์ฝ๋)์ ์ญํจ์.
ํ์ผ ํฌ๋งท : [8๋ฐ์ดํธ LE = ์๋ณธ ๋นํธ์ N] + [์ธ์ฝ๋ฉ ๋นํธ์คํธ๋ฆผ, ๋ฐ์ดํธ ์์์ LSB-first]
์ฝ๋์๋ : (nbits-1)๊ฐ์ 1 โ 0 โ count ์ nbits ๋นํธ(LSB-first)
๋ณต์ : count ๊ฐ์ 0 ๋นํธ + 1 ๋นํธ ํ๋ ๋ฅผ ์ด์ด ๋ถ์ฌ N ๋นํธ๋ฅผ ์ฑ์ด๋ค
(encode 0xc60 ์ `test eax,eax; je` ๊ฐ '0 ์ ์ธ๋' ๋ฃจํ๋ผ๋ ์ ์ด ํต์ฌ)
"""
import sys
class BitReader:
def __init__(self, data):
self.d = data
self.n = len(data) * 8
self.p = 0
def bit(self):
i = self.p
if i >= self.n:
raise EOFError
self.p = i + 1
return (self.d[i >> 3] >> (i & 7)) & 1
def decode(blob):
n_bits = int.from_bytes(blob[:8], 'little') # src->cap = ์๋ณธ ๋ฐ์ดํธ์ * 8
br = BitReader(blob[8:])
out = bytearray((n_bits + 7) // 8) # 0 ์ผ๋ก ์์ โ 0 ๋นํธ๋ ๊ทธ๋ฅ ๊ฑด๋๋ด๋ค
pos = 0
while pos < n_bits:
try:
k = 0 # 0 ์ด ๋์ฌ ๋๊น์ง 1 ์ ์ผ๋ค โ nbits = k+1
while br.bit():
k += 1
count = 0
for j in range(k + 1): # count ์ ๋นํธ๋ฅผ LSB-first ๋ก
count |= br.bit() << j
except EOFError:
break
pos += count # 0 ์ด count ๊ฐ
if pos < n_bits: # ๋ฐ์ ๋๋ด๋ 1
out[pos >> 3] |= 1 << (pos & 7)
pos += 1
return bytes(out[:n_bits // 8]), pos, n_bits
if __name__ == '__main__':
src, dst = sys.argv[1], sys.argv[2]
blob = open(src, 'rb').read()
res, pos, n_bits = decode(blob)
open(dst, 'wb').write(res)
print(f'{src} ({len(blob)}B) -> {dst} ({len(res)}B), ๋ณต์ ๋นํธ {pos}/{n_bits}')์๋ณธ ๋นํธ ์ n_bits ๋ก ๋๋ ๊ฒ ์ค์ํ๋ค. flush ๊ฐ ๊ผฌ๋ฆฌ๋ฅผ 1 ๋ก ์ฑ์ ๋จ๊ธฐ ๋๋ฌธ์, ๋๊น์ง ์ฝ์ผ๋ฉด
์์ง๋ ์์ ์ฝ๋์๋๋ฅผ ๋ช ๊ฐ ๋ ๋ง๋ค์ด ๋ธ๋ค. ๊ธธ์ด๋ฅผ ์๊ณ ์์ผ๋ ๊ฑฐ๊ธฐ์ ๋ฉ์ถ๋ฉด ๊ทธ๋ง์ด๋ค.
๐ Full Exploit
๋ณต์ํ PNG ๋ 10000ร10000 ์ง๋ฆฌ๋ผ ๊ทธ๋ฆผ ์ ์ฒด๋ฅผ ๋์ผ๋ก ํ๊ธฐ๊ฐ ๋ฒ๊ฑฐ๋กญ๋ค. ๋ฐฐ๊ฒฝ์ด ์์ ํ ๊ฒ์ ์ด๊ณ ๊ธ์๋ง ํฐ์์ด๋ผ, ์ํฌ๊ฐ ์๋ ์์ญ์ ๊ฒฝ๊ณ ์์๋ฅผ ๊ตฌํ๋ฉด ๊ธ์ ์ค์ด ๋ฐ๋ก ์กํ๋ค. ๋ค๋ง ์ค๋ฅธ์ชฝ์ ๋ฌ๋ ์์ด์ฝ์ด ํ๋ ๋ ์์ด์ ๊ฒฝ๊ณ ์์๋ฅผ ๊ทธ๋๋ก ์ฐ๋ฉด ์ธ๋ก๋ก ๋๋ฌด ๊ธธ์ด์ง๋ค. ์ด ๋จ์๋ก ์ํฌ ํฉ์ ๋ด์ ๊ฐ์ฅ ๋์ ๋น ๊ตฌ๊ฐ์ ์ฐพ๊ณ ๊ทธ ์ผ์ชฝ๋ง ๋จ๊ธฐ๋ฉด ๊ธ์ ์ค๋ง ๋จ์ด์ง๋ค.
๊ฑฐ๊ธฐ๊น์ง ์๋ฅด๋ฉด tesseract ๊ฐ ๋ฐ๋ก ์ฝ๋๋ค. ํ ๊ฐ์ง ์ฃผ์ํ ์ ์ ์ธ๊ทธ๋จผํ
์ด์
๋ชจ๋๋ค.
๊ธฐ๋ณธ๊ฐ์ด๋ --psm 7 ๋ก ์ฝ์ผ๋ฉด ๋ฐ์ค์ ๊ณต๋ฐฑ์ผ๋ก ๋ฑ์ด์ GoN{run length encoding} ์ด ๋๋๋ฐ,
--psm 13(raw line) ์ผ๋ก ์ฝ์ผ๋ฉด ๋ฐ์ค์ด ์ด์๋๋ค.
#!/usr/bin/env python3
"""Run (DreamHack Platinum 4) โ flag.enc ํ ๋ฐฉ ๋ณต์.
1) flag.enc ๋ฅผ ์ญRLE-gamma ๋ก ํ์ด ์๋ณธ PNG ๋ฅผ ๋์ด๋ฆฐ๋ค (decode.py)
2) ๋์ด๋ฆฐ 10000x10000 PNG ์์ ์ํฌ๊ฐ ์๋ ์์ญ์ ์ฐพ๊ณ , ์ค๋ฅธ์ชฝ ๋ฌ๋ ์์ด์ฝ์
๊ฐ์ฅ ๋์ ๋น ์ด ๊ตฌ๊ฐ์์ ์๋ผ๋ด ๊ธ์ ์ค๋ง ๋จ๊ธด๋ค
3) ๊ทธ ์กฐ๊ฐ์ tesseract ๋ก ์ฝ์ด flag ๋ฌธ์์ด์ ๋ฝ๋๋ค
"""
import re
import subprocess
import sys
from PIL import Image, ImageOps
from decode import decode
Image.MAX_IMAGE_PIXELS = None # ์ฐ๋ฆฌ๊ฐ ๋ฐฉ๊ธ ๋ง๋ ํ์ผ์ด๋ผ ํญํ ๊ฒฝ๊ณ ๋ ๋ฌด์๋ฏธํ๋ค
SRC = sys.argv[1] if len(sys.argv) > 1 else 'extracted/flag.enc'
PNG = sys.argv[2] if len(sys.argv) > 2 else 'flag.png'
CROP = 'flag_crop.png'
def split_off_icon(ink):
"""์ด ๋จ์ ์ํฌ ํฉ์์ ๊ฐ์ฅ ๊ธด ๋น ๊ตฌ๊ฐ์ ์ฐพ์ ๊ทธ ์ผ์ชฝ(=๊ธ์ ์ค)๋ง ๋๋ ค์ค๋ค."""
w, h = ink.size
col = [0] * w
px = ink.load()
for x in range(w):
s = 0
for y in range(0, h, 4): # 4ํ๋ง๋ค ํ์ด๋ ๋น ์ด ํ์ ์๋ ์ถฉ๋ถํ๋ค
s += px[x, y]
col[x] = s
best_len, best_end, run = 0, 0, 0
for x in range(w):
if col[x] == 0:
run += 1
if run > best_len:
best_len, best_end = run, x
else:
run = 0
if best_len < 40: # ๋๋ ทํ ๊ณต๋ฐฑ์ด ์์ผ๋ฉด ํต์งธ๋ก ์ด๋ค
return ink.getbbox()
cut = best_end - best_len + 1
return ink.crop((0, 0, cut, h)).getbbox()
def main():
blob = open(SRC, 'rb').read()
png, pos, n_bits = decode(blob)
open(PNG, 'wb').write(png)
print(f'[1] {SRC} ({len(blob)}B) -> {PNG} ({len(png)}B), ๋ณต์ ๋นํธ {pos}/{n_bits}')
print(f'[1] magic = {png[:8].hex(" ")}')
im = Image.open(PNG)
print(f'[2] ๋ณต์๋ ์ด๋ฏธ์ง: {im.size[0]}x{im.size[1]} {im.mode}')
gray = im.convert('L') # ์ํ๋ฅผ ๋ฒ๋ฆฌ๊ณ ๋ฐ๊ธฐ๋ง ๋ณธ๋ค
ink = gray.point(lambda p: 255 if p > 40 else 0)
box = ink.getbbox()
print(f'[2] ์ํฌ ์ ์ฒด ์์ญ = {box}')
sub = ink.crop(box)
tb = split_off_icon(sub)
text_box = (box[0] + tb[0], box[1] + tb[1], box[0] + tb[2], box[1] + tb[3])
print(f'[2] ์์ด์ฝ์ ๋ ๊ธ์ ์์ญ = {text_box}')
crop = gray.crop(text_box)
ImageOps.expand(ImageOps.invert(crop), border=60, fill=255).save(CROP)
print(f'[2] {CROP} ์ ์ฅ ({crop.size[0]}x{crop.size[1]})')
raw = subprocess.run(['tesseract', CROP, '-', '--psm', '13'],
capture_output=True, text=True).stdout.strip()
print(f'[3] tesseract ์๋ฌธ = {raw!r}')
m = re.search(r'GoN\{[^}]*\}', raw)
print(f'[3] FLAG = {m.group(0) if m else "(๋ชป ์ฐพ์)"}')
return 0 if m else 1
if __name__ == '__main__':
sys.exit(main())python3 solve.py
๋ณต์ํ ๊ทธ๋ฆผ์ด ์ค์ ๋ก ์ด๋ป๊ฒ ์๊ฒผ๋์ง๋ ๋ณด์. 10000ร10000 ์ 1000ร1000 ์ผ๋ก ์ค์ด๊ณ , ๊ธ์ ์ค๋ง ์๋ณธ ํด์๋๋ก ํ ๋ฒ ๋ ์๋ผ ๋ธ๋ค.
#!/usr/bin/env python3
"""๋ณต์ํ flag.png ๋ก ๊ธ์ ๋ฃ์ ๊ทธ๋ฆผ ๋ ์ฅ์ ๋ง๋ ๋ค.
12_preview.png : 10000x10000 ์๋ณธ์ 1000x1000 ์ผ๋ก ์ค์ธ ์ ์ฒด ๋ฏธ๋ฆฌ๋ณด๊ธฐ
13_flag.png : ๊ธ์ ์ค๋ง ์๋ผ๋ธ ์๋ณธ ์(๊ฒ์ ๋ฐฐ๊ฒฝ ํฐ ๊ธ์) ์กฐ๊ฐ
"""
from PIL import Image
Image.MAX_IMAGE_PIXELS = None
OUT = '/home/jinho/homepage/public/images/blog/dreamhack-run-writeup'
im = Image.open('flag.png').convert('RGB')
im.resize((1000, 1000), Image.LANCZOS).save(f'{OUT}/12_preview.png')
print(f'12_preview.png <- {im.size[0]}x{im.size[1]} ๋ฅผ 1000x1000 ์ผ๋ก')
box = (3900, 9140, 8120, 9540) # solve.py ๊ฐ ์ฐ์ด ์ค ๊ธ์ ์์ญ์ ์ฌ๋ฐฑ์ ๋ํ ๊ฐ
im.crop(box).save(f'{OUT}/13_flag.png')
print(f'13_flag.png <- crop{box} = {box[2] - box[0]}x{box[3] - box[1]}')python3 make_figs.py
๊ฑฐ์ ์ ๋ถ๊ฐ ๊ฒ์ ์ด๋ค. ์ธ์ฝ๋ฉ ๊ฒฐ๊ณผ๊ฐ 3๋ถ์ 1 ๋ก ์ค์ด๋ ์ด์ ๊ฐ ์ด๊ฑฐ๋ค. ๊ฒ์ ํฝ์ ์ด ์ด์ด์ง๋ ๊ตฌ๊ฐ์์ 0 ๋ฐ์ด ์์ฃผ ๊ธธ์ด์ง๊ณ , ๋ฐ ํ๋๊ฐ ์๋ฌด๋ฆฌ ๊ธธ์ด๋ ์ฝ๋์๋๋ ๋ช ์ญ ๋นํธ๋ฅผ ๋์ง ์๋๋ค.
์ค๋ฅธ์ชฝ ์๋๋ฅผ ์๋ณธ ํด์๋๋ก ์๋ฅด๋ฉด ํ๋๊ทธ๊ฐ ๋์จ๋ค.

GoN{run_length_encoding} ์ด๋ค. ๋ฌธ์ ์ด๋ฆ ๊ทธ๋๋ก๋ค.
ํ๋๊ทธ๊ฐ ๋ฌธ์์ด์ด ์๋๋ผ ๊ทธ๋ฆผ์ผ๋ก ๋ ๋๋ผ ์์ผ๋, ๋ฐ์ด๋๋ฆฌ๋ ๋ณต์๋ณธ์ด๋ strings ๋ grep ์ผ๋ก๋
์์ํ ์ ์กํ๋ค. flag.enc ๋ฅผ ์๋ฌด๋ฆฌ ๋ค์ ธ๋ GoN ์ด ์ ๋์ค๋ ๊ฒ ์ ์์ด๋ค.
โ ๊ฒ์ฆ โ ๋ณต์๋ณธ์ ๋ฌธ์ ๋ฐ์ด๋๋ฆฌ์ ๋ค์ ๋จน์ธ๋ค
๋ณต์์ด ๋ง๋์ง ํ์ ํ๋ ๊ฐ์ฅ ํ์คํ ๋ฐฉ๋ฒ์ ๋ฌธ์ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ค๋ผํด๋ก ์ฐ๋ ๊ฒ์ด๋ค.
๋ด๊ฐ ๋์ด๋ฆฐ flag.png ๋ฅผ ๊ทธ๋๋ก main ์ ํต๊ณผ์ํค๋ฉด, ๋ชจ๋ธ์ด ์ ํํ ๋๋ง ๋ฐฐํฌ๋
flag.enc ์ ๋ฐ์ดํธ ๋จ์๋ก ๊ฐ์ ํ์ผ์ด ๋์จ๋ค.
#!/usr/bin/env bash
# ๋ณต์ํ flag.png ๋ฅผ ๋ฌธ์ ๋ฐ์ด๋๋ฆฌ์ ๊ทธ๋๋ก ์ฌํฌ์
ํด ๋ฐฐํฌ๋ณธ flag.enc ์ ๋์กฐํ๋ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
mkdir -p roundtrip && cp flag.png roundtrip/flag.png
( cd roundtrip && ../extracted/main flag.png )
sha256sum roundtrip/flag.png.enc extracted/flag.enc
if cmp -s roundtrip/flag.png.enc extracted/flag.enc; then
echo "MATCH: ์ฌ์ธ์ฝ๋ฉ ๊ฒฐ๊ณผ๊ฐ ๋ฐฐํฌ๋ณธ๊ณผ ๋ฐ์ดํธ ๋จ์๋ก ๊ฐ๋ค"
else
echo "DIFF: ๋ชจ๋ธ์ด ํ๋ ธ๋ค"; exit 1
fi./roundtrip.sh
sha256 ์ด ๊ฐ๋ค. ๋นํธ ์์, ์ฝ๋์๋ ๋ฌธ๋ฒ, ๋ฐ์ ๋์, ๊ผฌ๋ฆฌ ํจ๋ฉ, ํค๋๊น์ง ์ ๋ถ ๋ง์๋ค๋ ๋ป์ด๊ณ , ๋์ผ๋ก ๊ทธ๋ฆผ์ ๋ณด๊ณ "๋ง๋ ๊ฒ ๊ฐ๋ค" ๊ณ ํ๋จํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๊ฐํ ์ฆ๊ฑฐ๋ค.
๋ณต์๋ณธ์ด ์กฐ๊ธ์ด๋ผ๋ ๋ค๋ฅด๋ฉด ๋ฐ ๊ตฌ์กฐ๊ฐ ํต์งธ๋ก ์ด๊ธ๋ ๊ฒฐ๊ณผ ํ์ผ ํฌ๊ธฐ๋ถํฐ ๋ฌ๋ผ์ง๋ค. ๊ทธ๋ฆผ์ด ๊ทธ๋ด๋ฏํด ๋ณด์ด๋ ๊ฒ๊ณผ ์๋ณธ๊ณผ ๊ฐ์ ๊ฒ์ ๋ค๋ฅธ ์ด์ผ๊ธฐ๋ผ, ๋๊ฐ๊ธฐ ๋ฌธ์ ์์๋ ์ด๋ฐ ์๋ณต ๊ฒ์ฌ๋ฅผ ํ ๋ฒ ๋๋ ค ๋๋ ๊ฒ ํธํ๋ค.
๐ ๊ฒฐ๋ก
์ธ๋ ๋์์ ๋ฐ๋๋ก ์ฝ์ด๋ ํ๋ก๊ทธ๋จ์ ์๋ฌด ๋ถํ์ ํ์ง ์๋๋ค.
je ํ๋๊ฐ jne ์๋ค๋ฉด ์ด ๊ธ์ ์ ๋ฐ์ด ํ์ ์์๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ ์ค์๋ ์์ธ๋, ๊ธธ์ด ๋ถ์ผ์น๋,
ํ์ฑ ์ค๋ฅ๋ ๋ด์ง ์๋๋ค. ์ ํํ ๊ฐ์ ๊ฐ์์ ๋นํธ๋ฅผ ์ ํํ ๋ฐ๋ ๊ฐ์ผ๋ก ๋ฑ์ ๋ฟ์ด๋ค.
์กฐ๊ฑด ๋ถ๊ธฐ์ ๋ฐฉํฅ์ "๋์ถฉ ์ด์ชฝ์ด๊ฒ ์ง" ๋ก ๋๊ธฐ๋ฉด ์ ๋๊ณ , ์ ํ ๋์ ์ฃผ์๊ฐ ์ค์ ๋ก ๋ฌด์์
ํ๋ ์๋ฆฌ์ธ์ง ํ ๋ฒ ๋ ํ์ธํด์ผ ํ๋ค.
ํฌ๋งท์ ํ์ ํ ๋๋ ๊ธธ์ด๊ฐ ์๋๋ผ ๋ด์ฉ์ผ๋ก ํ์ ํ๋ค.
๋ณต์ ๋นํธ ์๊ฐ ํค๋์ ๋ฑ ๋ง์๊ธฐ ๋๋ฌธ์ ๋๋ ํ๋์ ๋์ฝ๋๋ฅผ ์์ฌํ์ง ์์๋ค.
๋งค์ง ๋๋ฒ, ์ฒดํฌ์ฌ, ํ์ผ ๋์ ์ข
๊ฒฐ ๊ตฌ์กฐ์ฒ๋ผ ๊ฐ ์์ฒด๊ฐ ๊ฑธ๋ฆฌ๋ ์งํ๋ฅผ ํ๋ ์ก์ ๋๋ฉด
์ด๋ฐ ์ฐฉ๊ฐ์ด ์ค๋๊ฐ์ง ์๋๋ค. ์ด ๋ฌธ์ ์์๋ 89 50 4e 47 ์ด ๊ทธ ์ญํ ์ ํ๋ค.
์ง์ ๋ง๋ ์ธ์ฝ๋ฉ์ ๋น๋ฐ์ด ์๋๋ค.
์ด ๋ฌธ์ ์ flag.enc ๋ ์ํธ๊ฐ ์๋๋ผ ์์ฒด ์ ์ ์์ถ์ด๋ค. ํค๋ ์๊ณ ๋์๋ ์์ด์
์ธ์ฝ๋ 1810๋ฐ์ดํธ๋ง ์ฝ์ผ๋ฉด ์์ ํ ๋ณต์๋๋ค. ์ค๋ฌด์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ถ ๋ชฉ์ ์ผ๋ก
์ฌ๋ด ํฌ๋งท์ ์ฐ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ, ์ธ์ฝ๋ ๋ฐ์ด๋๋ฆฌ๊ฐ ํจ๊ป ๋ฐฐํฌ๋๋ ์๊ฐ
๊ทธ๊ฑด ๊ทธ๋ฅ ์ด๋ ค ์๋ ๊ฒ์ด๋ค. ๊ฐ์ถฐ์ผ ํ ๊ฐ์ ํฌ๋งท์ด ์๋๋ผ ํค๋ก ๊ฐ์ธ์ผ ํ๋ค.
ํ๋๊ทธ๋ฅผ ๋ฌธ์์ด์ด ์๋๋ผ ๊ทธ๋ฆผ์ผ๋ก ๋๋ ์ถ์ ๋ฐฉ์.
strings ยท grep ยท ์ ์ ๋ฌธ์์ด ์ค์บ ๊ฐ์ ์ง๋ฆ๊ธธ์ ์ ๋ถ ๋ง๋๋ค.
๋ณต์๋ ๋ฐ์ดํฐ๊ฐ ํ
์คํธ๊ฐ ์๋๋ฉด ๋ ๋ํด์ ๋์ผ๋ก ๋ด์ผ ํ๊ณ , ๊ทธ๋ฌ๋ ค๋ฉด ํฌ๋งท์
๋๊น์ง ์ ํํ ๋์ด๋ ค์ผ ํ๋ค. ์ด ๋ฌธ์ ๊ฐ Platinum ์ธ ์ด์ ๋ ๊ธฐ๋ฒ์ด ์ด๋ ค์์๊ฐ ์๋๋ผ,
์ค๊ฐ์ ๋์ถฉ ๋ง์ถ ์ํ๋ก๋ ์๋ฌด๊ฒ๋ ๋ชป ๋ณด๊ธฐ ๋๋ฌธ์ด๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ