pwnable
[pwnable.xyz] door write up
[pwnable.xyz] door write up
2020.08.10Analytic 이번 문제는 `main()` 함수와 `win()` 함수 2개만 있다. `main()` 함수를 보면 사용자가 입력한 값을 write 하는 것만 있다. int main(){ setup() puts("Door To Other RealmS") int32_t var_14 = 0 int32_t var_10 = 0 *door = rand():0.d while (true) print_menu() uint64_t rax_2 = zx.q(read_int32():0.d) if (rax_2:0.d != 2) if (rax_2:0.d s> 2) if (rax_2:0.d != 3) if (rax_2:0.d == 4) return 0 // rax_2 == 3 else if (*door == 0) continue e..
[pwnable.xyz] car shop write up
[pwnable.xyz] car shop write up
2020.08.09Analytic `Full RELRO` 이기 때문에 GOT overwrite를 할 수 없다. `buy()` 함수를 보면 사용자가 선택한 자동차가 메모리 공간에 저장된다. 이때의 메모리 구조를 보면 아래와 같다. `0x603260` ~ `0x6032af`: 사용자가 `buy()` 함수를 호출하면 `car`라는 구조체의 chunk가 만들어짐 `0x603260`: 자동차 이름을 저장한 주소 `0x603268`: 자동차 이름의 크기 `0x603270`: 다음 청크(`car`)의 주소 `0x603278`: 이전 청크(`car`)의 주소 `0x603290`: 자동차의 이름 gdb-peda$ x/10gx 0x603260 0x603260: 0x0000000000603290 0x0000000000000003 0x6032..
[pwnable.xyz] words write up
[pwnable.xyz] words write up
2020.08.08Analytic 아래 사진은 사용자 정의 함수 목록이다. fill_letters(), fill_numbers(), fill_handles(), fill_words() 함수들은 특별한 기능은 없고 사용자 선택에 따라 문장을 만들어 출력하는 함수 이다. 하지만 fill_handles() 함수를 제외한 나머지 함수들은 만들어진 문장으로 초기화 하여 생성하지만, fill_handles() 함수는 로직 에러로 초기화를 하지 않고 문장을 추가한다. 코드로 자세히 설명하자면, 사용자가 select1 값이 2가 아니고 select2 값이 6이상이면 문장을 초기화 하지 않는다. 이 로직 에러로 문장을 계속 추가 할 수 있게 된다. 문장이 저장되는 메모리 공간은 아래와 같다. 문장이 저장되는 시작 부분은 변수 a인 0x6..
[pwnable.xyz] notebook write up
[pwnable.xyz] notebook write up
2020.08.07바이너리 파일을 분석하여 c로 나타내면 아래와 같다. void make_note(){ printf("size: "); int size = read_int(); void* addr = malloc(0x38); *(addr + 0x30) = malloc(size); *(addr + 0x8) = size; *addr = &get_size(); printf("Title: "); readline(addr + 0xc, 0x1f, 0xa); printf("Note: ") readline(*(addr + 0x30), size, 0xa); *data_602300 = addr; } void edit_note(){ int addr = *data_602300; if(addr != 0){ addr = *(*data_602300..
[pwnable.xyz] nin write up
[pwnable.xyz] nin write up
2020.08.07이번 문제는 UAF 관련 문제이다. 해당 바이너리에는 아래와 같은 보안 장치가 설정되어 있다. 바이너리를 c코드로 변환하면 아래와 같다. void hash_gift(arg1, arg2){ int result1 = 0; int result2 = 0; int count = 0; while(true){ if(count >= int(arg2/2)) break; result1 = result1 + *(arg1 + count); count++; } for(int i = int(arg2)/2; i 0x2; eax = eax >> 0x1f; edx = edx - eax; eax = edx; eax = eax 사용자가 입력한 값 (크기: 사용자가 입력한 길이에 따라 다름) 0x603280 ==> invite_reznor..
[pwnable.xyz] note v2 write up
[pwnable.xyz] note v2 write up
2020.08.05해당 바이너리에는 아래와 같은 보안 기법이 적용되어 있다. 또한 아래 사진처럼 여러개의 사용자 정의 함수들의 존재하는 것을 볼 수 있다. 사용자 정의 함수들 중 아래 make_note() 함수를 보자. 기본적으로 0x28 만큼 공간을 할당하고, 사용자로 부터 크기를 입력받아 공간을 할당한다. 만약 *(addr + 0x20) 에 값이 들어가 있으면 공간을 할당 하지 않는다. void make_note(){ if(count
[pwnable.xyz] - dirty tultle write up
[pwnable.xyz] - dirty tultle write up
2020.04.15pwnable.xyz 34번째 문제 dirty turtle 이다. Analyze 이번 문제의 사용자 정의 함수를 보면 아래와 같다. ubuntu:~/environment/ctf/pwnable.xyz/34_Dirty turtle $ func challenge __libc_csu_fini __libc_csu_init _fini _init _start get_val handler main setup win checksec으로 바이너리에 적용된 보안 기법을 보면 아래와 같다. ubuntu:~/environment/ctf/pwnable.xyz/34_Dirty turtle $ checksec --file=challenge RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORT..
[pwnable.xyz] badayum write up
[pwnable.xyz] badayum write up
2020.03.10pwnable.xyz 30번째 문제이다. 해당 바이너리의 사용자 정의 함수를 보면 존재 하지 않았다... ubuntu:~/environment/ctf/pwnable.xyz/30_badayum $ func challenge nm: challenge: no symbols 그래서 gdb로 main 함수를 찾고 play(?) 함수와 win() 함수를 찾았다. 이를 c코드로 나타내면 아래와 같다. /* main: 0x555555554ead play??: 0x555555554d48 win: 0x555555554d30 */ long play(){ int tmp_1 = 0; // rbp-0x74 int tmp_2 = 0; // rbp-0x78 while(tmp_1 edx = 0x1f4e9d7e) edx = edx 0x..
[pwnable.xyz] Hero Factory write up
[pwnable.xyz] Hero Factory write up
2020.03.10pwnable.xyz 33번째 문제이다. Analyze 해당 바이너리에서 사용자 정의 함수들을 보면 아래와 같다. ubuntu:~/environment/ctf/pwnable.xyz/33_Hero Factory $ func challenge __libc_csu_fini __libc_csu_init _fini _init _start createHero crossfit deleteHero floss getInt hadouken handler main printFnc printHero printMenu printSuperPowers setup usePower win wrestle zeroHero gdb로 바이너리를 분석하여 c코드로 나타내면 아래와 같다. (분석 환경이 gdb 밖에 없는 내 자신이 대단..) v..
[zer0pts 2020 CTF] hipwn write up
[zer0pts 2020 CTF] hipwn write up
2020.03.09zer0pts 2020 CTF 문제 중 pwnable 분야의 hipwn 이다. 문제 파일을 다운로드 하면 chall, main.c 파일이 존재한다. main.c 코드 내용은 아래와 같다. #include int main(void) { char name[0x100]; puts("What's your team name?"); gets(name); printf("Hi, %s. Welcome to zer0pts CTF 2020!\n", name); return 0; } ubuntu:~/environment/ctf/zer0pts/pwn/hipwn $ checksec --file=chall RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fort..
Aero 2020 CTF write up - aerofloat
Aero 2020 CTF write up - aerofloat
2020.03.03Aero 2020 CTF 문제 중 pwnable 분야의 Aerofloat 문제이다. 대회 당일에는 풀지 못했지만, 롸업을 보고 재 도전 후 풀수 있게 되었다. Analyze 해당 문제의 바이너리 안에 사용자 정의 함수는 아래와 같다. ubuntu:~/environment/ctf/Aero CTF 2020/pwn/Aerofloat $ func aerofloat main menu read_buf read_int gdb로 문제 바이너리를 분석해서 c로 나타내면 아래와 같다. void menu(){ puts("1. Set rating"); puts("2. View rating list"); puts("3. View porfile info"); puts("4. Exit"); printf("> "); } int re..
[pwn] - pwntools 로 PIE base 구하기
[pwn] - pwntools 로 PIE base 구하기
2020.02.23바이너리에 PIE가 걸려 있다면, 디버깅 할때 주소가 랜덤으로 바뀌어 breakpoint를 걸 수 가 없다. 하지만 PIE base를 구할 수 있다면, 주소가 랜덤으로 바뀌어도 breakpoint를 걸 수 있다. 바로 아래 코드가 중요하다. pie_base = p.libs()["바이너리 절대 경로"] 간단한 예를 보면 다음과 같다. from pwn import * context.terminal = ['tmux', 'splitw', '-h'] context.log_level = 'debug' p = process("./challenge") e = ELF("./challenge",checksec=False) pie_base = p.libs()["/home/ubuntu/environment/ctf/pwnabl..
[pwn] - environ 변수로 stack leak 하기
[pwn] - environ 변수로 stack leak 하기
2020.02.23environ 변수를 이용해 stack leak 를 하는 방법이다. 이 공격을 하기 위해 다음과 같은 가정이 필요하다. libc base 주소를 알고 있다. 임의의 주소를 leak 할 수 있다. gdb-peda$ p 0x00007ffff79e4000 + 0x861a5c8 $2 = 0x7fffffffe5c8 gdb-peda$ p environ $3 = (char **) 0x7fffffffe5c8 gdb-peda$ x/gx $rsp 0x7fffffffe4d8: 0x00007ffff7a05b97 gdb-peda$ p 0x7fffffffe5c8 - 0x7fffffffe4d8 $4 = 0xf0 gdb-peda$ libc base address: 0x00007ffff79e4000 environ offset: 0x8..