상세 컨텐츠

본문 제목

[LOB] level 20: xavius -> death_knight

SYSTEM HACKING/LOB Redhat

by koharin 2019. 6. 30. 21:20

본문

728x90
반응형

 

#include <errno.h> : 소켓 생성 시 성공하면 빈 소켓의 파일기술자가 생성되지만, 소켓 생성 실패시 -1이 리턴되고 errno에 에러 코드가 저장된다. 따라서 errno.h 헤더파일을 사용한 것 같다.

char buffer[40] : buffer의 크기 40

struct sockaddr_in server_addr : sockaddr_in 구조체의 변수 server_addr => server 주소

struct sockaddr_in client_addr : sockaddr_in 구조체의 변수 client_addr => client 주소

if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) perror(“socket”); exit(1)

: AF_INETsocket의 인수에서 domain으로서 IPv4 네트워크 도메인 소켓으로 원격지까지 통신할 수 있다. (물론 로컬 호스트와 통신을 위해 로컬 루프백의 주소(ex. 127.0.0.1)에 연결 가능)접두어 AF_Address Family의 의미이다.

소켓 타입을 의미하는 SOCK_STREAMsockettype 인수로 스트림 소켓을 의미한다. SOCK_STREAM의 특징은 연결 지향형(connection oriented)으로, 연결을 맺고 1:1 통신을 한다. 연결 지향형인 SOCK_STREAM 소켓 타입을 구현한 프로토콜로 TCP가 대표적이고 일반적이다.

Cf. SOCK_DGRAM 소켓 타입은 비연결 방식이 특징적으로 일회성 데이터나 응답이 필요없는 작은 데이터 조각들을 전송할 때 유리하고, 1:n 통신이 가능하다. 데이터그램 소켓은 하나의 소켓으로 여러 원격지로 송신하거나 여러 원격지로부터 데이터를 수신할 수 있다.

세 번째 인수인 protocol은 전송에 사용될 프로토콜 타입을 의미한다. 이 부분에 보통 0이나 IPPROTO_IP로 지정한다. (IPPROTO_IP0으로 지정되어 있어서 둘 중 아무거나 사용해도 상관 X) IPPROTO_IP는 지정된 소켓 타입에 의거해 인터넷 프로토콜을 자동으로 세팅한다.  

 

 

 

perror 함수는 perror 함수 내 인자인 문자열 serror message로 출력하는 함수이다.

int socket(int domain, int type, int protocol);

socket의 함수 원형인데, server_fd, server의 소켓이 IPv4 네트워크 도메인 소켓, 스트림 소켓이 아니면 종료된다.

server_addr.sin_family = AF_INET : server_addr은 구조체 변수이므로 구조체 연산자를 사용해 sin_family라는 멤버를 AF_INET으로 할당했다. IPv4 도메인 네트워크 소켓으로 한 것이다.

 

server_addr.sin_port = htons(6666) : serverport 번호를 6666으로 지정했다.

 

 

htons 함수는 hostshort6666이라는 host byte order network byte order로 변환하는 역할로 사용되었다.

 

 

bzero(&(server_addr.sin_sero), 8)

bzero 함수는 처음 문자열 s의 처음 n byte0으로 만든다. 따라서 serversin_zero 멤버 변수 주소의 8byte0으로 만든다.

if(bind(server_fd, (struct socketaddr *)&server_addr, sizeof(struct socketaddr)) == -1)

perror(“bind”); exit(1);

bind는 socket으로 생성된 빈 소켓이 시스템 장치와 통신할 수 있도록 이름을 부여하는 과정이다.

bind로 이름이 부여되어야만 외부 인터페이스와 연결되고 이후 통신이 가능하다.

(빈 소켓은 외부 연결점이 없는 상태이므로 통신 불가)

소켓 생성 시 IPv4 기반 네트워크 도메인 소켓(AF_INET)을 사용했으므로 bind에는 IP, 포트 번호를 부여하는 작업을 할 것이다. (네트워크 도메인에서 외부와 소통할 수 있는 인터페이스는 IP 주소와 포트 번호를 의미)

client 측에서 connect 과정에서 bind를 내포하므로 bind가 주로 생략됨

★ accept : client가 connect() 호출을 통해 victim server에 접속 요청한 것을 수락. 

성공 시 client와 1:1로 연결된 파일기술자 리턴

★ send: client에 데이터 송신. 따라서 client는 server가 보낸 데이터를 받기 위한 recv 함수 필요

recv(client_fd, buffer, 256, 0) : client로부터 데이터 수신. buffer의 크기는 40byte로 정해져있는데 256 byteclient로부터 받아서 bufferoverflow 발생

★ close:  연결 끊으려면 server나 client 측에서 아무나 close() 또는 shutdown() 호출해 close 함.

 

위의 코드는 server 측의 코드에 해당한다.

따라서 server가 보내는 데이터를 받고, 데이터를 보내기 위한 client 코드를 작성하여야 한다.

 

코드의 구성은 server 코드와 비슷한데, client 측에 맞도록 socket 생성, bind는 생략, connect로 server 측에 연결 요청, server 측에서 보낸 데이터 수신을 위한 recv, 서버에 공격 위한 send로 구성된다.

 

신경써야 할 부분은 똑같이 payload를 전달하는데

buffer(40) + sfp(4) + ret(4) + NOP(100) + shellcode

여기서 ret에 들어가는 대상 서버 binary의 정확한 return address를 알 수 없다.

따라서 bruth forcing으로 구해서 payload에 대입한다.

이때 LOB 서버에서 stack segment 주소는 0xbfff0000 ~ 0xbfffffff 이므로 하위 2 byte만 구하면 된다. (0xbfff 제외)

따라서 이중 for문을 구현하여 0xff ~ 0x00 사이의 두 byte를 반복해서 돌려 ret에 대입하면서 맞는 주소를 구한다.

(구해진 이후에도 계속 bruth forcing되므로 정확한 주소는 알 수 없고

성공하면 victim server와 connect 되었다고 출력됨)

 

여기서 사용하는 shellcode는 지금까지와는 다른 bind shell이다.

https://resources.infosecinstitute.com/icmp-reverse-shell/#gref

 

victim이 server, client가 attacker라서 client가 server에 공격 shell을 전달하는 경우이다. 

이 문제에서 server가 client의 연결을 기다리고 데이터를 송신 후 client로부터 recv로 데이터를 수신하므로 client가 server에 공격이 가능한 것이다. 또한 원래 buffer 40 byte보다 큰 256 byte를 받으므로 bufferoverflow가 가능하다.

 

 

 

host는 공격자는 IP 주소 $ ifconfig로 출력된 IP 주소로 사용

port는 well-known port 이후인 1024 ~ 65535 중 임의의 번호로 사용 => 9998 선택

 

host와 port 모두 16진수로 변환

 

bind shell 사이에 host, port를 넣어줌

s변수 사용 이유는 파이썬 코드 상 socket.socket()으로 소켓 생성하므로 이후 편의를 위한 것

connect 함수에는 연결할 서버의 IP 주소($ /sbin/ifconfig)와 지정된 포트 번호를 인자로 넣어 server에 연결 요청

for문으로 ret 주소의 하위 2 byte를 0xff ~ 0x00 범위에서 계속 대입해보면서 구함.

addr를 출력하는 print문은 있어도 되고 없어도 된다.

victim server 측에서 send를 통해 데이터를 보내므로 공격 전 일단 데이터 수신을 위해 recv 

이 후 victim server에서 client가 보낸 데이터를 recv를 통해 buffer로 받으므로 send로 payload 전달

close는 server 측에서 하므로 없어도 상관없다.

 

이제 python 코드는 완성됐고, attacker 측에서 

$ nc -lvp 9998

명령을 통해 지정한 포트로 포트를 열어두고(server와 통신을 위해)

listening하는 동안 다른 터미널을 열어서 

$ python exploit.py

로 작성한 파이썬 코드를 실행하면 공격이 시작된다.

 

이렇게 빠르게 bruth forcing하면서 주소를 계속 payload에 대입하고 server에 payload를 전달하는 동안,

 

 

맞는 주소를 대입하면 공격에 성공해 패스워드를 얻을 수 있다.

 

"got the life"

728x90
반응형

'SYSTEM HACKING > LOB Redhat' 카테고리의 다른 글

관련글 더보기