■ Level10 -> Level11
■ 목적
공유 메모리에 데이터 읽고 쓰기
프로세스와 프로세스가 통신(메세지를 주고 받는 방법)
-소켓 사용하는 경우(EX: Clint/Server 프로그램) cs프로그래밍 이라고 한다. server - client 통신
[EX] 서울버스 어플리케이션
화면 구성이나 메뉴는 스마트폰(client)에 있고, 실제 버스의 데이터는 Server에 존재한다.
어플(client)이 서버로부터 데이터를 갖고 와서 화면에 출력하는 방식.
-공유메모리를 사용하는 방법(EX: DB 프로그램(Oracle))
DB에 여러 데몬들이 같은 메세지를 가지고 작업해야할 때
-파일을 사용하는 경우
가장 성능이 떨어지는 방식
-DB 사용하는 경우
DB에 정보를 요청해서 빼가는 방식
-기타
이번 레벨에서는 공유메모리를 사용하는 방법을 사용한다.
보안적인 요소에서 공유메모리를 쓰고 있는 대표적인 경우
-암호화/복호화 방식(핵심 : Key)
ssh 암호화 방식(암호화 알고리즘, 평문형태 입력값 <--키값)
A의 ASCII 값 + 암호키 (+3 / 3) = A(41) + 3 / 3 = 44 나누기 3이 키값이 된다.(사칙연산)
마스터키가 메모리안에 상주하게 된다.
다른서버 l 서버 l 메모리
+-->---->--->----> l l<---<---<----+
+--<-----<----<--- l l -->--->------+
부팅시 서버의 암호를 다른서버에서 받아서 메모리에 넣어두고 메모리에서 받아 사용한다.
메모리 할당된 번호를 알면 조인 할 수 있다. (메모리는 수행이 끝나면 초기화 된다.)
암호알고리즘과 키의 변천과정
1. 초기모델에는 시스템에 암호알고리즘과 Key가 같이 있어서 디버그를 통해 알아낼 수 있었다.
2. 이후에 공격자가 시스템에 암호알고리즘이 Key를 가리키고 있어서 Key의 위치, 환경을 알 수 있었다.
3. 최근에는 Key Server (EX: Kerberos)를 제공하는 서버가 자동으로 연동되어 로컬에다가 키를 집어넣는다. 암호화할때 쓰고 재부팅되면 사라지고 부팅하면 새로운 키를 받아서 사용한다.
4. 새로운방식으로 Key Server가 시스템(파일형식)에다 제공하지 않고 메모리의 특정한 Key를 저장한다. 메모리내용은 초기화되고 다시 받고해서 해커들이 메모리 안을 읽기 시작했다. 프로그램이 어떤 메모리안에 있는것을 읽어들인다고 되어있으나, 메모리 어디로 올라갈지 모르고 쪼개셔서 들어간다. 메모리 ID값이 있으면 접근할 수 있어서 해커들이 ID값을 찾기 시작했다. ID값은 프로그램안에 들어 있을 것이고, 찾기 어렵게 하드코딩되어 있다.
■ Level10 풀이
level8 사용자 로그인
-> ID/PASS : level10/interesting to hack!
$ cat hint
그 대화방은 공유 메모리를 이용하여 만들어졌으며,
key_t의 값은 7530이다. 이를 이용해 두 사람의 대화를 도청하여
level11의 권한을 얻어라.
- 레벨을 완료하셨다면 소스는 지우고 나가주세요.
이 문제는 공유메모리와 key_t 에 포커스가 맞추어져 있는 것 같다.
그리고 소스를 지우라고 하니 코딩이 필요한 문제 인것 같다.
공유 메모리는 쉽게 해석하면 보통 프로세스는 각자의 메모리공간을 가지게 되는데, 프로세스간의 통신이
필요해져 여러 프로세스가 한 메모리 공간을 사용하며, 서로 통신을 하고 수행 속도도 원할하게 만드는
메모리 기술 이다.
결과적으로 한 메모리공간을 여러 프로세스(프로그램)가 사용하는 것 이다.
ipcs
ipc(프로세스들의 통신)설비 정보를 출력한다.
ipcs [Options]
옵션 |
의 미 |
-i |
특정 id에 대한 정보를 알 수 있습니다. 뒤에 해당 id를 적어야 합니다. |
-m |
공유 메모리 세그먼트정보를 출력합니다. |
-q |
메세지 큐 정보를 출력합니다. |
-s |
세마포어 배열 정보를 출력합니다. |
-a |
m, q, s 의 모든 리소스 정보를 출력합니다. |
-t |
시간 정보가 보여집니다. |
-p |
pid 정보가 보여집니다. |
-c |
만든사용자가 보여집니다. |
-l |
각 리소스의 제한 정보를 보여줍니다. |
-u |
각 리소스의 현황을 보여줍니다. |
$ ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00001d6a 0 root 666 1028 0
0x46532e4f 65538 trainer1 777 5 0
------ Semaphore Arrays --------
key semid owner perms nsems
------ Message Queues --------
key msqid owner perms used-bytes messages
위 정보를 보면 0x00001d6a 16진수를 10진수로 변환하면 7530값이 나온다.
현재 key 값이 7530이고 소유자는 root 허가는 0666 용량은 1028인 공유메모리가 있는걸 확인 할 수 있다.
이 공유 메모리에 나의 프로세스로 접속해서 대화내용을 볼 수 있다.
$ find / -user level11 -perm -4000 2>/dev/null
$ find / -user level11 2>/dev/null
$ find / -type f -exec egrep -l /home/level10/program {} \; 2>/dev/null
/prog/14265/cmdline
/etc/rc.d/rc.local
.....( 시간이 오래 걸린다 )...
=> 이 파일에 이런것이 들어있다는 것이 의심스러운 일이다.
(실무에서 많이 쓰는 명령어)
$ find / -type f -exec grep -l <단어> {} \;
$ find / -type f | xargs grep -l <단어> - 인자값을 '-' 자리로 보낸다.
$ 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 static하게 설정하기 위해 주석처리 해본적이 있다.
$ ps -ef | grep level
level10 3572 3571 0 21:50 pts/1 00:00:00 -bash
level10 3604 3572 0 21:50 pts/1 00:00:00 ps -ef
level10 3605 3572 0 21:50 pts/1 00:00:00 grep level
=> /home/level10/program/level10 프로그램은 데몬 모드로 동작하는 것은 아니고
일반 프로세스 형태로 한번 실행되고 끝나는 것 같다.
(실행되면서 메모리에 무언가를 올리고 초기화 되어 끝나는 것으로 추정)
부팅이 실행된다. -> 7530 메모리 사용중 -> 접속 가능
추측 의사코드를 코딩한다.
$ cd tmp ; vi shm.c
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
int main() {
int shmid;
char *address;
key_t key = 7530;
shmid = shmget (key, 0, IPC_CREAT);
address = shmat (shmid, 0, SHM_RDONLY);
printf("%s", address);
return 0;
}
[참고]공유 메모리 관련 함수에 대해서
코딩전 기초 알아야 할 것
공유메모리 관련함수( C언어)
1. shmget
공유메모리 공간을 요청하는 함수 입니다. 요청은 커널에 합니다.
shmget(key, size, shmflg)
*key : 공유메모리 Key 값, 이 값을 통해 커널에서 공유메모리를 선택해 접근 가능합니다.
*size : 공유메모리의 크기입니다. 최초생성시에는 크기를 지정해야 하나, 존재하는 메모리를 그대로 사용하 면 0으로 입력하면 됩니다.
*shmflg : 공유메모리의 생성방식입니다. 2가지가 있습니다.
1) IPC_CREAT : 첫번째 식별자인 key 값이 없을시 새로 만듭니다. 뒤에 "|" 을 붙여 접근권한 설정이 가능합니다. 만약 이미 key가 존재한다면 존재하는 공유메모리의 식별자를 리턴합니다.
2) IPC_EXCL : 해당 key를 가진 공유메모리 존재할 경우, 실패값을 반환하고 메모리에 접근을 통제 합니다.
결과적으로 shmget은 공유메모리의 식별자를 리턴(int)하게 됩니다.
2. shmat
현 프로세스가 공유메모리를 사용가능하도록 하는 함수 입니다. 공유메모리 식별자에 공유메모리 세그먼트를 붙이기 위해 사용합니다.
shmat(shmid, shmaddr, shmflg)
*shmid : 공유메모리의 식별자입니다. shmget함수에서 나온 결과
*shmaddr : 메모리가 붙을 주소입니다. 0을 지정하면 커널에서 자동으로 지정해줍니다.
*shmflg : 동작모드 3가지 있습니다.
1) SHM_RDONLY : 읽기전용으로 동작합니다.
2) SHM_RND : shmaddr을 반올림해 메모리 페이지 경계에 맞춥니다.(shmaddr이 null이 아닐때만 사 용됩니다. )
3) 아무것도 없을경우 : 읽기/쓰기 전용으로 동작합니다.
결과적으로 공유메모리 식별자에 대한 주소를 리턴하게 됩니다.
3. shmdt
프로세스가 공유메모리를 더 사용하지 않을 경우 그 둘을 분리하는 함수 입니다.
shmdt(shmaddr)
*shmaddr : 공유메모리 주소입니다. 해당 주소가 분리됩니다.
해당 함수를 동작시키면 현프로세스가 공유메모리에서 분리되고 shmid_ds의 내용을 커널이 갱신합니다.
4. shmctl
공유메모리를 제어하는 함수 입니다.
shmctl(shmid, cmd, shmid_ds *buf)
*shmid : 공유메모리 식별자
*cmd : 제어명령
1) IPC_STAT : 공유메모리에 관한 정보를 buf에 저장합니다.
2) IPC_SET : 공유메모리 공간에 대한 권한 변경을 합니다.
3) IPC_RMID : 공유메모리 공간을 삭제합니다.
4) SHM_LOCK : 공유메모리 세그먼트를 잠급니다.
5) SHM_UNLOCK : 공유메모리 세그먼트 잠금을 해제합니다.
*shmid_ds *buf : 공유메모리 정보를 구할 수 있는 버퍼 포인터 입니다.
$ gcc -o shm shm.c
$ ./shm
멍멍 : level11의 패스워드는?
구타 : what!@#$?
구타와 멍멍은 오래전 hackerschool에서 사용하던 닉네임이다. 실존했던 사람들
[참고] 참고 사이트
■ 의사코드
■ 복원 의사코드
위에서 사용한 추측 코드를 참조해서 의사코드를 분석한다.
$ cd ; cd program (root계정)
$ gdb level10
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <main+0>: push %ebp
0x08048471 <main+1>: mov %esp,%ebp
0x08048473 <main+3>: sub $0x8,%esp
0x08048476 <main+6>: sub $0x4,%esp
0x08048479 <main+9>: push $0x3b6
0x0804847e <main+14>: push $0x404
0x08048483 <main+19>: push $0x1d6a
0x08048488 <main+24>: call 0x804832c <shmget>
0x0804848d <main+29>: add $0x10,%esp
0x08048490 <main+32>: mov %eax,%eax
0x08048492 <main+34>: mov %eax,0x80496d0
0x08048497 <main+39>: sub $0x4,%esp
0x0804849a <main+42>: push $0x0
0x0804849c <main+44>: push $0x0
0x0804849e <main+46>: pushl 0x80496d0
0x080484a4 <main+52>: call 0x804834c <shmat>
0x080484a9 <main+57>: add $0x10,%esp
0x080484ac <main+60>: mov %eax,0x80496cc
0x080484b1 <main+65>: sub $0x8,%esp
0x080484b4 <main+68>: push $0x8048560
0x080484b9 <main+73>: pushl 0x80496cc
0x080484bf <main+79>: call 0x804835c <strcpy>
0x080484c4 <main+84>: add $0x10,%esp
0x080484c7 <main+87>: leave
0x080484c8 <main+88>: ret
0x080484c9 <main+89>: lea 0x0(%esi),%esi
0x080484cc <main+92>: nop
0x080484cd <main+93>: nop
0x080484ce <main+94>: nop
0x080484cf <main+95>: nop
End of assembler dump.
■ 복원 의사코드
#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=7530;
sharedMemID=shmget(keyval, BUFFSIZE, IPC_CREAT | 0666);
sharedMemory=shmat(sharedMemID, (void *)0, 0);
memcpy(sharedMemory, buf, BUFFSIZE);
shmdt(sharedMemory);
return 0;
}
#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=7530;
// 공유 메모리의 ID를 읽어 온다.
sharedMemID=shmget(keyval, BUFFSIZE, 0666);
// 프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(Attach) 한다.
sharedMemory=shmat(sharedMemID, (void *)0, 0);
// 공유 메모리 공간에 있는 값을 특정 변수에 복사한다.
memcpy(buf, sharedMemory, BUFFSIZE);
printf("%s", buf);
// 프로세스에서 공유 메모리의 연결을 분리(Detach)한다.
shmdt(sharedMemory);
return 0;
}
■ 원본 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *text;
int shmid;
int main( void ) {
shmid = shmget((key_t)7530, 1028, 0666 | IPC_CREAT);
text = shmat(shmid, (void *)0, 0);
strcpy(text,"멍멍: level11의 패스워드는?\n구타: what!@#$?\n");
}
[
원본 소스에선 shmdt는 하지 않았지만 동작에는 이상없이 잘 작동한다.
'Learning > └◆Reversing' 카테고리의 다른 글
11_Level11 -> Level12[FTZ] 포맷스트링(Format string directive) 취약점 (0) | 2017.01.30 |
---|---|
[참고]공유 메모리 관련 함수 (0) | 2017.01.30 |
09_Level9 -> Level10[FTZ] 버퍼 오버 플로우 소개 (0) | 2017.01.29 |
[참고] 버퍼 오버 플로우 (0) | 2017.01.29 |