fedora 원정대 core 3 hell_fire -> evil_wizard

fedora 원정대 core 3 hell_fire -> evil_wizard

evil_wizard.c


hint 를 보면 GOT overwritting이 써있다. GOT overwritting 공격을 시도하여 쉘을 얻을 수 있다.

strcpy함수에서 overflow가 발생하여 eip를 원하는 곳으로 이동 시킬수 있게된다.
eip를 strcpy의 plt(고정주소)로 이동시켜 strcpy함수를 호출할 수 있고 ret에 poppopret가젯의 주소를 넣어 rop공격코드를 작성 할 수 있다.

strcpy를 이용하여 memset의 got에 system함수의 주소를 1바이트씩 복사 할 것이다. 그러면 memset을 호출하게되면 결국 memset의 got에 덮어씌여진 system함수를 호출 하게된다.

system함수에 인자로 들어갈 '/bin/sh'문자열도 위와 같은 rop 방식으로 strcpy함수를 호출하여 memcpy의 got에 복사하여 system함수의 인자로 넘겨 줄 것이다.

이제 필요한 주소들을 찾고 코드를 작성하면 된다.

먼저 poppopret가젯의 주소는


poppopret의 주소는 0x0804854f이다.

execve로 덮힘을 당할 memset@plt와 memset got를 찾는다.


memset@plt의 주소는 0x08048474이다.



got의 memset주소는 0x08049898이다.
got의 memcpy주소는 0x080498c0이다.


system의 주소는 0x007507c0이다.


strcpy@plt의 주소는 0x08048494이다.

필요한 got, plt주소는 구했으니

system의 주소, /, b, i, n, /, s, h가 있는 주소를 다 구하고 strcpy를 이용해서 1바이트씩 덮어 써야한다.


이렇게 전부다 뒤져서 익스플로잇 코드를 작성한다.


ret부분에 strcpy가 덮이고 인자로 덮힘당할 memsetgot의 주소와 덮을 문자의 주소가 들어간다. strcpy함수가 끝나면 poppopret 이 수행되어 인자 두개를 제끼고 다시 strcpy함수로 들어가는 rop이다.

공격을 하면


쉘을 얻을수 있다.

쉘코드:

Read more

fedora 원정대 core3 dark_eyes -> hell_fire

fedora 원정대 core3 dark_eyes -> hell_fire

hell_fire.c


sfp를 복사해 두었다가 원상복귀 시키고 fgets로 받은 문자를 strcpy하는 과정에서 스택을 조작할 수 있다. tcp 7777로 remote환경이다.

다른사람들의 라이트업을 참고해보니 do_system으로 eip를 이동시켜서 쉘을 얻는 것을 볼 수 있었다. do_system이 무엇일까..


system 함수에서 do_system을 호출하는 것을 볼 수 있었다.
system 함수는

#include <stdlib.h>

int system(const char *string)

이고 /bin/sh -c string을 호출하여 string명령어를 실행하고 fork()와 execve()의 조합으로 실행된다.


do_system함수를 까보면 함수의 밑부분에 sigaction(), sigprocmask()를 호출하고 execve()함수를 호출 하는 것을 볼 수 있다. eip를 sigaction쪽으로 이동시키면 쉘을 얻을 수 있는데 지식이 부족해서 왜 그런지 알수가 없다. execve가 실행되서 얻는것같은데 모르겠다



??

 (python -c 'print "A"*268 + "\x7f\x07\x75\x00"';cat) | nc localhost 7777
Read more

linux system call

linux system call

mlock() 메모리의 페이지 잠금
munlock() 메모리의 페이지 잠금 풀기
mlockall() 호출한 프로세스의 페이징을 금지시킨다.
munlockall() 호출한 프로세스에 대한 페이징을 다시 가능하도록 한다.
sched_setparam() 스케줄 파라미터 설정
sched_getparam() 스케줄 파라미터 설정값 가져오기
sched_setscheduler() 스케줄 알고리즘 파라미터 설정
sched_getscheduler() 스케줄 알고리즘 파라미터 값 가져오기
sched_rr_get_interval() 프로세스의 SCHED_RR간격을 가져온다
nanosleep() 지정한 시간에 실핼을 잠시 멈춘다.
mremap() 가상 메모리 주소를 재대응 시킨다.
poll() 파일 지정자로부터 이벤트를 기다린다.
chown() 파일 소유자 변경
getcwd() 최근 작업 디렉토리 가져오기
vfork() 자식 프로세스 생성, 부모 프로세스 주소공간에서 동작
clone() 자식 프로세스의 생성
setdomainname() 도메인 이름 설정
uname() 최근 커널의 정보 얻어오기
sigprocmask() POSIX 시그널 제어 관련 함수
create_module() 적재 가능한 모듈 엔트리 생성
init_module() 적재 가능한 모듈 엔트리 초기화
delete_module() 적재 모듈의 삭제
getpgid() 프로세스 그룹아이디 가져오기
readdir() 디렉토리 내용을 읽어들인다
select() 입출력 다중화
readv() 벡터를 읽는다
writev() 벡터를 쓴다
sys_getdis() 세션리더의 프로세스 아이디를 가져온다
sysctl() 시스템 파라미터를 읽고 쓴다
reboot() 리붓 시킨다
munmap() 메모리 페이지 해제
truncate() 파일의 길이 결정
ftruncate() 파일의 길이 결정
getpriority() 프로그램의 우선순위 얻어오기
setpriority() 프로그램의 우선순위 설정
socketcall() 소켓 시스템 콜
syslog() 커널 메시지 버퍼의 내용을 읽거나 클리어 한다
setitimer() 내부 타이머 설정
getitimer() 내부 타이머 값 가져오기
wait4() 프로세스릐 종료를 기다린다. BSD스타일
swapoff() 파일/장치의 스와핑 끝내기
sysinfo() 시스템의 정보 얻어오기
fsync() 파일의 내부상태와 디스크상의 상태를 동기화 한다
sigreturn() 시그널 핸들러와 클린업 스택 프레임으로 부터 반환
sigaction() POSIX 시그널 제어 함수
sigsuspend() 시그널 마스크를 일시적으로 대체한 후 시그널을 기다린다.
sigpending() 시그널을 블럭하고 검사를 수행한다.
sethostname() 호스트이름 설정
setrlimit() 자원의 제한값을 설정한다.
getrlimit() 자원의 제한값을 얻어온다
gettimeofday() 날짜와 시간을 얻는다
settimeofday() 날짜와 시간을 설정한다
getgroups() 포함된 그룹 아이디의 목록을 얻는다
setgroups() 포함될 그룹 아이디의 목록을 설정한다.
symlink() 파일에 대한 심볼릭링크 생성
lstat() 파일의 상태 얻기
readlink() 심볼릭 링크의 연결된 파일 이름을 읽는다.
uselib() 공유라이브를 선택한다.
swapon() 파일과 장치의 스와핑을 시작한다.
dup() 열린 파일 지정자를 복사한다.
pipe() 내부 통신을 위한 채널을 생성한다.
times() 프로세스 시간을 얻는다.
setgid() real 그룹 아이디를 설정한다.
getgid() real 그룹 아이디를 얻어온다.
geteuid() effective 유저 아이디 가져오기
getegid() effective 그룹 아이디 가져오기
ioctl() 장치 제어
fcntl() 파일 제어
umask() 파일 마스크의 생성
chroot() 루트디렉터리의 변경
dup2() 파일 지정자 복사
getppid() 부모 프로세스의 PID얻기
getpgrp() 프로세스의 그룹 아이디 얻기
setsid() 세션과 프로세스 그룹 아이디 설정
chown() 파일의 소유자 변경
stat() 파일의 상태 얻기
lseek() 파일에서의 위치 변경
getpid() 프로세스의 ID얻어온다
setuid() 실제 유저 아이디 설정
getuid() 실제 유저 아이디 얻어오기
alarm() 실정시간후 alarm시그널이 전달되도록 한다
fstat() 파일 상태 얻기
pause() 시그널이 전달될 떄까지 대기한다.
access() 파일의 권한을 검사한다.
sync() 슈퍼블럭을 업데이트 한다
kill() 프로세스에 시그널을 전송한다
rename() 파일의 이름과 위치를 변경한다
mkdir() 디렉터리를 생성한다
rmdir() 디렉터리를 제거한다.
exit() 현재 프로세스의 종료
fork() 자식 프로세스의 생성
read() 파일 디스크립터로부터 읽기
write() 파일 디스크립터로 쓰기
open() 파일이나 장치열기
close() 파일 디스크립터 닫기
waitpid() 프로세스의 종료를 기다린다
creat() 파일이나 장치의 생성
link() 파일을 위한 새로운 이름 만들기
unlink() 파일 혹은 참조된 이름을 삭제한다
execv() 프로그램의 실행
chdir() 작업 디렉터리의 변경
time() 초 단위의 시간 얻기
mknod() 일반 혹은 특수파일의 생성
chmod() 파일의 권한 변경하기
Read more

fedora 원정대 core3 iron_golem -> dark_eyes

fedora 원정대 core3 iron_golem -> dark_eyes

dark_eyes.c


sfp를 백업 해두었다가 오버플로우가 발생한 이후에 sfp를 원상복귀 시킨다.
sfp는 사용할 수 없고 ret를 조작 할 수 있다. hint에 RET sleding이 써있다.
RET sleding을 사용하여 스택영역을 벗어난 후에 execve함수를 실행하면 execve함수의 인자로 고정적인 문자열을 넣을 수 있다.그 문자열을 이용하여 쉘을 얻어본다.


간단하게 쉘을 얻을수 있는 프로그램을 작성하고 컴파일한다. 위의 dark_eyes의 권한으로 execve를 이용해 위의 쉘을 얻는 프로그램을 실행하면 쉘을 얻을 수 있다.

ret와 execve함수의 주소를 찾아본다.

execve
ret

ret sleding을 태워서 스택을 벗어난 후 execve를 실행하도록 코드를 작성한다.

./dark_eyes `python -c 'print "A"*268 + "\xfe\x82\x04\x08"*8 + "\x90\x54\x7a\x00"'`

이 코드를 돌리면 execve의 인자로 이상한 것이 들어가서 에러가 발생한다.
strace를 사용하여 execve의 인자로 들어가는 고정바이트를 찾을 수 있다.

strace ./dark_eyes `python -c 'print "A"*268 + "\xfe\x82\x04\x08"*8 + "\x90\x54\x7a\x00"'`


execve로 알수 없는 문자열이 들어간다. strace의 표준에러출력을 리다이렉션으로 저장하여 xxd를 사용하면 execve로 들어가는 문자열의 헥사값을 알 수 있다.

위의 쉘을 얻는 프로그램에 execve로 들어가는 문자열로 심볼릭 링크를 걸어주고 위의 쉘코드를 실행하면 쉘을 얻을 수 있다.


Read more

raspberry pi linux kernel compile

raspberry pi linux kernel compile

라즈베리파이에서 디바이스 드라이버를 작성하거나 커널을 수정하기 위해서는 라즈베리파이의 커널 소스를 참조하여 컴파일하기 때문에 라즈베리파이의 커널 소스를 다운 받아야한다.

라즈베리파이의 커널소스와 툴은 github에서 다운받을 수 있다.

git clone http://github.com/raspberrypi/linux.git
git clone http://github.com/raspberrypi/tools

나는 작업디렉터리를 $HOME으로 홈으로 설정하고 홈밑에 linux, tools디렉터리를 받았다.

먼저 커널컴파일과 드라이버컴파일등에 필요한 라즈베리파이커널용 컴파일러를 PATH에 등록하여 사용하기 쉽게 해보자.


/home/dorkiz/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
의 경로에 가면 툴들이 있다.

~/ 경로에 .bashrc파일에 이 툴들의 경로를 추가해준다.


그러면 환경변수에 설정되어 바로 참조할 수 있다.

그리고 라즈베리파이에 맞는 커널 컴파일 설정을 해준다.
arm-linux-gnueabi-gcc를 찾을수 없다는 에러가 떳었는데 워크피시 리눅스를 32비트 바꾸고 해결 할 수 있었다.


컴파일 설정을 해주고나면 make로 커널을 컴파일 할 수 있다.


컴파일 과정은 한 15분정도 걸린다.
컴파일이 완료되면 /home/dorkiz/linux/arch/arm/boot 디렉터리가 생성된다.


커널 Image와 압축된 zImage가 있다
컴파일된 커널 Image 파일은 바로 사용할 수 없기 때문에 kernel.img로 바꾸어 주어야한다.
이전에 받은 툴중에 로드가능한 라즈베리 파이용 커널 이미지를 만드는 툴이 있다.


/home/dorkiz/tools/mkimages/imagetool-uncompressed.py
를 사용하여 /home/dorkiz/linux/arch/arm/boot/zImage를 kernel.img로 바꾸어준다.

이제 라즈비언이 설치되어있는 SD카드 안에 kernel.img를 방금 만든 kernel.img로 교체하고 SD카드를 부팅하면 내가 컴파일된 kernel.img가 로드되게 된다.
Read more

ARM assembly 공부, bof

ARM assembly를 공부하기 위해서 bof redhat 원정대 1번 문제를 ARM환경에서 컴파일하고 단순하게 어셈블리어만 라인바이라인으로 분석해보고 x86 리눅스에서와 어떤식으로 다른지 확인 해 보았다.

bof 1번 문제의 c코드


strcpy에서 버퍼의 크기를 확인하지 않아 버퍼오버플로우가 발생 될 것으로 예상된다.

c코드 바이너리의 어셈블리어코드


서브루틴으로 진입시 r11, rl 을 사용하여 분기오피코드와 서브함수의 PUSH {r11, lr}로 SFP와 RET를 백업 한다. argv는 r0. r1로 전달한다.
함수를 빠져 나올때는 POP {r11, pc}로 스택프레임과 돌아갈 주소를 복귀시켜준다.
여기서 POP되는 스택을 조작하면 이전처럼 pc를 조작 할 수 있을것 같다.


첫번째 네모가 r11로 팝될 놈이고 두번째 네모가 pc로 팝될 놈이다.
두번째 네모를 덮어 pc를 조작 할 수 있어 보이나 안해봐서 확실하지 않다ㅋ
Read more

gdb script을 이용한 편리한 디버깅환경 만들기

$(HOME)/.gdbinit을 생성하면 gdb가 실행될 때 .gdbinit을 불러옴으로 스크립트를 적용시킬 수 있다.

ARM 어셈을 처음다루어 라인바이라인으로 분석해 보기위해 몇 가지 스크립트를 작성하였다.

.gdbinit














jk를 치면 info reg, x/i $pc, x/i $pc가 실행된다 가독성을 높이기 위해 x/i $pc를 두번 하였다.
jkst 를 치면 sp부터 스택을 보여준다


간단한 스크립트지만 사용해보면, 편리하다..
Read more