Post

(excp) 읽기 권한 없는 파일 복사하기

쓰기 권한으로 파일 복사하기

원래 읽기 권한이 있어야 파일 복사가 가능하도록 되어있지만, 실행 권한이 있는 경우 읽기 권한이 없어도 ptrace를 이용해 파일을 복사하여 내 소유 파일로 얻어낼 수 있다. 파일을 실행하게 되면 해당 파일이 메모리에 적재된다는 점을 이용하여, ptrace로 프로세스의 가상메모리 공간 중 실행한 파일이 매핑된 공간에 접근해서 데이터를 추출해 파일에 쓴다. 이렇게 얻어낸 파일은 원본 파일과 동일하게 동작하며, 얻어낸 파일에 gdb, strings 등을 사용할 수 있기 때문에 유용하게 활용할 수 있다.

* 얻어낸 파일이 원본 파일과 완전히 동일하지는 않다. file 명령어 등을 이용해 속성을 확인해보면 손상된 것으로(stripped) 나온다. readelf : 섹션 안나옴, objdump : 안됨, nm -D : 심볼 없는 것으로 나옴. gdb도 마찬가지로 symbol을 찾을 수 없다고 나온다. 그러나 직접 메모리 주소에 접근해서 bp걸고 디버깅하는 것은 가능하다.

excp

https://github.com/umbum/pwn/blob/master/tools/excp.c

실행 권한 파일 복사 프로그램. 다음과 같이 동작한다. fork, exec를 이용해 복사하고 싶은 프로그램을 child로 실행한 다음, procfs로 프로세스에서 실행한 파일이 매핑된 주소를 구하고, ptrace를 이용해 이 주소의 데이터를 읽어 파일에 쓴다.

fork 후 child에서 ptrace(PTRACE_TRACEME, ...)를 호출해 주어야 kernel이 exec를 수행하다 child에게 SIGTRAP을 보내게 된다. fork 후 parent에서 wait()를 호출하면 parent는 child의 종료 또는 상태변화를 기다리며 대기하게 된다. child가 SIGTRAP을 받으면 wait하던 parent가 재개된다.

2016/12/27 - [Coding] - fork - exec / wait

usage

1
excp SRC DST [-o|-m]

-o 옵션을 주면 구식OS로 간주하고 addr2start에 더했던 0x1000을 다시 뺀다. -m 옵션을 주면 직접 복사할 주소를 입력할 수 있다.

-o option

구식 OS :

  • r–p section이 없다.
  • 타인이 실행한 프로세스의 proc maps에도 접근이 가능하다.
  • r 권한이 없어도 proc maps에 접근이 가능하다.

최근 OS :

  • r–p section이 존재한다.
  • 타인이 실행한 프로세스일 경우 proc maps에 접근할 수 없다.
  • 내가 실행한 프로세스여도 r 권한이 없으면 proc maps에 접근할 수 없다.

뭐가 문제인지는 정확히 모르겠으나 최근 OS의 경우 r–p section까지 복사하면 Segmentation fault가 난다.

fgets로 2번째 line을 읽고, r–p이면 line을 한번 더 가져와 rw-p line의 주소를 얻으려고 했으나 프로세스 실행 직후에는 최근 OS도 구식 OS처럼 r–p section이 따로 없고 rw-p section에 포함되어 있기 때문에 다음 line을 가져오는 것이 의미가 없다.

그래서 그냥 두번째 line에서 얻은 addr2start에 0x1000을 더한 곳을 rw-p section으로 간주했다. r–p section 크기가 항상 0x1000라고 장담할 수는 없지만, 대체로 이 크기인 듯 싶다.

* 그리고 어차피 최근 OS는 r 권한 없으면 proc maps도 접근 불가하기 때문에 address를 유추해서 넣어줘야 한다.

-m option

Ubuntu 16.04에서는, 내가 실행한 파일이더라도 r 권한이 없으면 /proc/<pid>/maps 파일을 읽을 수 없다. 또는 타인의 권한으로 실행된 프로세스에 대해서도 읽을 수 없도록 되어있다. ( 그래서 setUID가 걸려있는 경우 읽을 수 없다. )

그러나 r-xp section의 시작지점이 대체로 0x08048000 이라는 점과

memory allocation은 page 단위로 이루어 진다는 점을 통해서 memory mapping address를 유추할 수 있다.

  1. 마지막 rw-p section이 끝나는 주소는 0x08048000 + ( filesize || filesize + 0x1000 || filesize + 0x2000 ) 으로 추정할 수 있다. (file size는 page size 단위로 올림해야 한다.)
  2. r–p section의 크기는 0x1000이다. 즉, r-xp section이 어디서 끝나는지만 결정하면, rw-p section의 범위는 자동으로 결정된다. r-xp section이 끝나는 주소를 정확히 알 수는 없지만, rw-p section의 크기도 0x1000인 경우가 대부분인 듯. 이게 안될경우, -m옵션을 주면 직접 복사할 주소를 입력할 수 있다. * 왜 0x08048000 +filesize + 0x2000이 최대 크기냐면, 각 section의 최소 크기가 0x1000이기 때문이다. filesize가 0x1555이고 r-xp section에 0x1001, rw-p section에 0x0554 만큼이 할당되어야 한다고 하면 page 단위로 할당되므로 r-xp section은 0x2000, r–p section은 0x1000, rw-p section은 0x1000 의 크기를 가지게 된다. filesize를 page 단위로 반올림해도 0x2000이니까, 0x2000만큼을 더 더해줘야 rw-p section이 끝나는 주소가 된다. 그러나 filesize에 0x2000을 더해야 하는 경우는 아직 보지못했고, 대부분 filesize 또는 filesize + 0x1000 이다.
참고

박찬암님의 hktrace

This post is licensed under CC BY 4.0 by the author.