목록전체 글 (111)
Sechack
처음으로 풀어본 CTF힙문제이다. 고득점 문제여서 풀고나서 매우 뿌듯했다. 프로그램은 매우 간단했다. 원하는 사이즈로 청크를 할당받을 수 있고 해제할 수 있다. add함수는 전역변수에 우리가 입력한 사이즈만큼 malloc을 한다. view함수는 전역변수에 들어있는 값을 출력해주고 있었다. delete 함수는 전역변수를 free해준다, PS: The challenge uses the good old Ubuntu 18.04 libc ;) 문제에서도 이렇게 힌트를 주면서 double free가 그냥 된다는것을 알려주고 있다. 실제로 double free에 대한 검증이 없는 libc였다. 근데 full relro가 걸려있었다. 역시 호락호락하게 풀리게 주진 않는다... got overwrite가 불가능하니 fr..
톡방이나 커뮤니티같은 곳에 있다보면 입문자 분들이 공통적으로 가장 많이 질문하시는 내용이기도 하고 저 또한 드림핵이라는 플랫폼을 알기 전까지 이것저것 삽질한 기억이 나서 글을 쓰게 되었습니다. 사실 보안에 입문하려면 프로그래밍 지식과 기초적인 컴퓨터 사이언스 지식은 베이스로 가져가야 합니다. 저는 입문하시려는 분들께 최소한 C, Python은 배우고 입문하라고 말하고 싶습니다. 해킹에는 크게 5가지 종류가 있습니다. 웹해킹, 리버싱, 포너블, 포렌식, 암호학(크립토)이라고 생각합니다. 그중에서 가장 대중적인 분야는 웹해킹, 리버싱, 포너블 이렇게 3가지인것 같습니다. 실제로 많은 입문자분들이 관심가지시는 분야는 웹해킹인것 같습니다. 이제 이 3가지 분야에 대한 공부 방법을 소개하여 보겠습니다. 먼저 웹해..
로되리안때문에 반나절을 날리다가 결국 플래그를 못얻은 문제이다. fd만 맞춰주면 되는건데... 흑... main의 디스어셈 결과를 보니까 init_seccomp함수로 seccomp를 설정하고 pwn dis shit를 출력하고 rbp-0x10에 0x200만큼 입력받는다. BOF가 터지는것이다. seccomp-tools로 본 결과 open. read. write를 이용해서 플래그를 읽어와야 할것 같다. 먼저 puts의 got를 출력해서 libc를 leak한 다음 다시 main으로 가서 open, read, write call chain을 구성하면 될것이다. open함수는 fd를 3부터 할당하니까 /pwn/flag.txt를 읽으면 fd가 3이 될것이다. (그런줄 알았다... 로컬에서 그렇길래 굳건히 믿었다....
바이너리가 굉장히 심플합니다. nasm으로 구현된것 같네요. vuln함수를 보면 rsp에 입력을 받으니까 ret를 조작할 수 있습니다. 위에 보니까 가젯들도 전부 제공해주고 있습니다. 한가지 문제점은 bss섹션이 존재하지 않고 .text섹션밖에 없어서 /bin/sh문자열을 저장할곳이 없습니다. 결국 스택을 이용해야 합니다. execve system call은 /bin/sh문자열 자체가 아닌 /bin/sh문자열이 저장된 메모리 주소를 필요로 합니다. sysrop를 진행할 가젯은 위에서 보시다시피 충분히 존재합니다. 스택에 /bin/sh문자열을 넣고 인자로 전달하려면 stack leak이 필요합니다. 하지만 leak할 방법이 없는것 같습니다. vuln함수에 입력받는 부분을 보면 mov rsi, rsp 즉 r..
main에서 myFun함수를 호출한다. 저 함수가 핵심기능이다. 하지만 디컴파일 해보려고 하면 에러가 뜨면서 디컴파일이 되지 않는다. 어쩔 수 없이 어셈블리어 수준에서 분석해야 한다. 옆에 보이는 win함수가 어셈 분석결과 fopen, fgets, printf를 이용해서 플래그를 출력해주는 함수였다. 저것도 마찬가지로 디컴파일이 되지 않는다. win함수이다. 주석부분만 봐도 flag.txt를 읽어서 출력해주는 함수임을 알 수 있다. myFun함수이다. name과 password를 입력받는다. ebp-0x20에 입력받는데 입력하는 크기는 0x150이어서 BOF가 터지는것을 알 수 있다. 그리고 ebp-0xc의 값을 0x0DEADBEEF와 체크해서 각각 분기한다. 하지만 자세히 보면 출력하는 문자열만 다를뿐..
처음에 디컴파일 결과보고 쫄았던 문제이다. 70줄이나 되었던... 원래같으면 포기하고 다른문제 풀었을탠데 한번 자신을 믿어보기로 하고 분석해봤다. 위에서도 말했지만 디컴파일 결과가 타 문제보다 길어서 쫄았다. 하지만 핵심만 파악하면 간단하게 익스플로잇 할 수 있는 문제였다. 위에 부분은 조금 잘렸는데 변수 선언부분이다. 근데 대회때 볼때는 디컴파일 결과 70줄이었는데 왜 지금은 67줄이지... 디컴파일 결과도 상황에 따라서 바뀌나보다. 보호기법은 카나리, NX, PIE가 걸려있다. 어차피 이 문제에서는 의미없으므로 신경쓰지 않아도 된다. 위에 코드를 분석하면서 프로그램을 한번 실행해보았다. 대충 실행해보니까 사용자가 입력한 길이만큼 리스트 만들고 원하는 함수주소 입력하면 우리가 만들었던 리스트 인자로 주..
main함수와 _read함수, 그리고 _start함수 3개만 덩그러니 있었다. gdb로 어셈블리어를 보니까 rbp-0x8에 입력받는데 0x200만큼 입력이 가능했다. 즉 sfp와 ret을 덮는게 가능하다. (gdb로 다시한번 더 본 이유는 IDA에서는 rbp-fd라고 출력이 되어서 정확한 확인을 위해 gdb로 한번더 보았다.) 근데 지금보니까 fd = dword ptr -8이라는게 상단에 보인다. 역시 static이다. 보호기법을 보니 NX가 해제되어 있었다. 이말은 즉 쉘코드 삽입이 가능하다는 말이다. 처음에는 syscall로 call chain을 구성해보자는 생각을 했으나 가젯이 너무나도 없었다. pop rax만 있어도 sigreturn을 사용해서 익스플로잇 했을텐데 rax를 조작해줄수 있는 가젯마저..
아이다로 보니까 뭔가 괴상하다. _start밖에 존재하지 않는걸로 보아 순수 어셈으로 구현된게 분명하다. 어셈가지고 무슨 이상한짓을 했는지 보니까 ret대신 jmp를 사용한다. 문제 설명란에도 영어로 무언가가 써있었는데 해석해보면 많은 포너들은 return address를 덮는것을 좋아합니다. 하지만 이번에는 그러지 못할것입니다. 대충 이런뜻이다. ret자체가 없기때문에 eip조작이 불가능하다. 하지만 __@8_return_address를 보면 edx에 0x1000이 들어가는데 rsi에는 rbp-0x100이 들어간다. 그리고 __@9_return_address를 보면 leave가 있다. 아직 이 부분들이 뭘 하는지는 모르지만 rbp-0x100을 rsi에 넣고 edx에 0x1000을 넣고 read를 호출하..
FSB문제를 풀다보면 주소를 2바이트, 1바이트 단위로 쪼개서 페이로드에 집어넣어야되는 상황이 흔하게 생긴다. (사실 2바이트 쪼개서 넣는게 가장 일반적인데 경우에 따라서 1바이트까지 쪼개야하는 경우가 생긴다.) 주소를 쪼개서 넣는이유는 한번에 넣어버리면 화면에 출력되는 시간이 너무 길다. (%n서식지정자는 출력된만큼 덮어쓰기 때문이다.) 바이너리에 따라서 익스플로잇 시간제한이 있을수도 있고 무엇보다 익스플로잇 시간이 너무 오래걸리기 때문에 주소를 쪼개서 넣어서 익스플로잇 시간을 단축하는것이다. 일단 주소 쪼개기의 예를 들자면 printf got를 system함수의 주소로 덮는다 가정해보자. printf got : 0x08048782 system addr : 0xf7ed8a40 라고 치고 offset이 ..
바이너리를 받자마자 ida로 까봤다. gets함수 부분에서 버퍼 오버플로우가 발생한다. 정확한 offset파악을 위해 gdb로 main함수를 까보았다. rbp-0x40부터 입력받는다. 그렇다면 0x48만큼 더미를 주면 rip를 변조할 수 있다. 바로 일반적인 rop페이로드 작성했다. very easy하게 풀리는줄 알았으나 잉? 처음에는 단순히 심볼을 못읽나보다 생각하고 직접 구하려고 gdb를 다시 까봤다. 음... 뭔가 이상하다... 설마 하고 static인지 확인해봤더니... 설마가 사람잡는다. static이었다...ㅠ 그러면 전형적인 rop처럼 libc의 execve나 system함수를 호출할 수 없다. 쉘코드 삽입은 nx때문에 안될것같고 syscall을 활용해야할것같았다. 순간 머릿속에서 드림핵에서..