pwn/HackCTF (11) 썸네일형 리스트형 HackCTF/ Unexploitable 4 IDA로 main함수 봤을때는 클났다 싶었는데 Unexploitable #3보다 쉬웠다 근데 내 로컬에서 분석했을때는 bss영역에 실행권한이 없었는데 다른 분들 풀이 보니까 있었다.... dreahack에서도 이거와 관련한 글이 있어서 나중에 하나하나 봐야겠다 https://dreamhack.io/forum/community/1612 왜 validator 문제는 푸는 사람에 따라 bss에 실행권한이 다를까? 대충 이 이야기의 시작은, 오래전 작년 12월로 넘어간다.. 오픈 카톡 채팅방에 정도비님이 물어보셨다. 내 컴퓨터에서는 bss 섹션에 X가 없는데, 다른 사람 라이트업을 보니 b… dreamhack.io write-up 단순한 stack buffer overflow가 터진다 어.... 난이도가 급격히.. jon9hyun's secret 카나리랑 PIE가 안 걸려있다 바이너리는 static compiled이고 stripped 되어있다... 이거본 순간 그대로 IDA 끄고 자러 갈 뻔했다 최대한 알아먹을 수 있게 함수명을 적어놓았다 main함수에서 힙 영역에 데이터를 입력받고 top_secret파일의 데이터를 출력한다 운이 좋았는지 처음에 심볼이 다 죽어있어서 strace로 실행시켜보는 과정에서 main함수 이전에 flag을 open하는걸 확인했다 from pwn import * context.log_level = "debug" p = remote("ctf.j0n9hyun.xyz", 3031) #p = process("./j0n9hyun_secret") #gdb.attach(p) payload = b"A" * 0x138 payload +=.. UAF 바이너리를 열어보면 노트를 추가, 삭제, 출력 기능이 있다 add_note함수에서는 먼저 8만큼의 힙을 할당받은 뒤 노트에 문자열이 될 힙을 원하는 크기만큼 할당받는다 print_note_content함수 주소와 문자열이 있는 청크의 주소는 처음 할당된 청크에 저장되고 이 청크 주소를 notelist에 저장한다 notelist에서 원하는 인덱스의 노트를 삭제시킬 수있다 (add_note에서 할당된 청크를 free시킨다) 문자열 데이터가 저장된 청크를 먼저 free시키고 add_note에서 처음 할당받은 청크를 free시킨다 notlist에 저장된 청크에 있는 함수를(print_note_content) 호출한다 del_note함수에서 할당된 청크를 free할때 notelist의 주소를 비워주지 않기 때문에.. ChildFSB 25byte만 가지고 fsb을 통해 익스해야되는 문제이다 fsb가 발생하고 카나리 1byte 덮을 수 있다 첫 fsb에서는 libc_start_main함수 leak하고 stack_chk_fail함수 2byte overwrite해서 다시 main으로 가도록 했다 그담에 onshot가젯으로 libc_start_main got주소 하위 3byte를 덮고 stack_chk_fail함수 got를 libc_start_main plt주소로 덮었다 from pwn import * p = remote("ctf.j0n9hyun.xyz", 3037) #p = process("./childfsb") libc = ELF("libc.so.6") #gdb.attach(p) cnry = 0x601020 start_main = 0x6.. hackCTF / Unexploitable #3 main함수에서 fgets를 통해 입력을 받으면서 bof가 터지고 rdx를 컨트롤할 가젯이 없어 rtc를 사용하기로 했다 leak하기 위해 fwrite을 사용 할 경우 rcx에 stdout의 주소를 pop rdi 가젯과 magic의 mov rcx, [rdi]를 차례대로 사용해 인자를 설정해주었다 뭐에 홀려서 그랬는지 모르겠는데 0x90다음에 0x100으로 넘어가는걸로 헷갈려서 0xa0만큼의 데이터만 사용해서 문제를 풀었다… ( ㅂㅅ쉨;) 지금 write up을 쓰면서 보니까 leak하고 다시 fget할 만큼 데이터를 충분히 받을 수 있었다... from pwn import * #context.log_level = 'debug' p = remote("ctf.j0n9hyun.xyz", 3034) #p = p.. ezshell shellcode 문제답게 nx bit가 걸려 있지 않고 코드내에서 syscall이나 0x3b 등의 바이트 필터링을 해서 바로 execve syscall을 수행할 수 없었다 또한 입력한 쉘코드가 실행되기 전에 rip를 제외한 모든 레지스터를 초기화시키기 때문에 rip를 제외하면 정보를 얻기가 매우 힘들다 from pwn import * p = process("./ezshell") #gdb.attach(p) shell = b"\x48\x8d\x35\xc9\xff\xff\xff\x48\x89\xf1\xfe\xc9\xfe\xc9\xb2\xff\xff\xe1" shell += b"A" * (30 - len(shell)) p.send(shell) sleep(1) ex_shell = b"\x48\x89\xf4\x4.. babyfsb fsb를 애매하게 이해한 것 같아 hackCTF의 babyfsb문제를 푸는데 대체 무슨 기준으로 leak이 되는지.. 등 기초가 많이 부실했구나 느끼게 해 준 문제였습니다 babyfsb write up도 쓸겸 부족한 부분을 정리해볼까 합니다 FSB는 주로 printf함수에서 발생하는 버그인데 포맷 스트링 즉 서식 문자를 잘못 사용하였을 때 생기는 게 됩니다 x64에서는 rdi -> rsi -> rdx -> rcx -> r8 -> r9 -> stack 순으로 인자가 저장됩니다 위의 그림을 참고해서 생각해보면 rdi레지스터에 서식 문자를 지정하여 주고 지정된 서식 문자는 다음의 인자들을 서식 문자에 맞게 출력해주게 됩니다 #include int main(){ printf("%lx\n%lx\n%lx\n%lx\.. Keygen 제목부터 역연산이겠구나 싶은 문제입니다 이미 많은 사람들이 푼 문제이기도 하고 풀고 나서 다른 분들 write-up보고 아... 나 정말 이상하게 했네 싶어서 글로 남기려고 합니다 main함수를 보면 check_key함수에 입력한 문자열이 들어가고 반환 값이 1이면 되면 플레그를 출력해줍니다 check_key함수를 보면 encoding함수 호출 후 strcmp함수를 통해 문자열과 비교하여 같고 그때 반환 값인 0이 면 1(True)을 반환하게 됩니다 encoding함수의 경우 일련의 연산을 수행하게 됩니다 여기서 a1[i]가 입력한 문자열이고 v2의 초기 값은 72이고 첫 연산 이후 encode 된 값이 들어갑니다 결국 encode된 값과 비교하기 때문에 여러 결과가 나올 수 있습니다 그래서 결국 비교하.. 이전 1 2 다음