ropasuarusrex는 32-bit ELF파일이고 NX만 걸려있다. 데이터영역에서 코드실행이 안되므로 쉘코드는 넣지 못한다.
아이다를 이용해서 메인부터 분석했다. 엄청 간단했는데
함수가 하나 있고 리턴값으로 WIN이 출력되어 나온다.
sub_80483F4함수 내부로 들어가니
buf가 136바이트 만큼 선언된다. 그렇지만 read함수에서 버퍼사이즈를 넘는 256바이트의 문자열길이까지 받도록 되어있다.
이부분에서 bof가 발생한다.
ida에 나와있는데 write@plt주소와 read@plt주소를 구해주고.
plt내부로 들어가면 jmp하는 부분이 있는데 [함수 호출]--->[PLT로 이동]--->[GOT 참조]
과정에 따라 노란줄부분의 주소가 각각 write@got, read@got의 주소값이다.
objdump -d ropasaurusrex 명령어를 통해 pppr의 가젯을 찾아준다. 왜 pppr인가?
=> read함수와 write함수 모두 세개의 인자를 갖기 때문이다.
objdump -h ropasaurusrex 명령어를 통해 "/bin/sh" 문자열을 넣어줄 영역을 찾는다.
bss영역을 이용하도록 한다.
ldd(List Dynamic Dependencies)는 프로그램이나 공유 라이브러리들이 요구하는 공유 라이브러리(shared libraries)를 출력하는 명령 행(Command Line)프로그램이다.
ldd명령어를 통해 ropasaurusrex가 사용하는 공유라이브러리를 알 수 있었고 aslr이 걸려있어서 주소가 매번 바뀌는 것을 볼 수 있었다. 그래서 프로그램이 실행되면 나오는 실제 read함수의 주소를 이용한다.
라이브러리 안에 있는 read와 system함수의 offset값의 차를 이용해서 페이로드에서 leak할 실제 read함수 주소에 더하면 실제 system함수의 주소가 나온다.
offset값의 차를 이용하는 이유?
libc내부에서 함수들의 사이 거리는 항상 일정하기 때문이다.
libc base address + system함수 offset = 실제read함수의 주소 +(system함수 offset - read함수 offset)
read offset - system offset = 0x9ad60
시나리오
준비물:
read_plt주소 / write_plt주소 / read_got주소 / write_got주소 / pppr주소 / bss영역 주소 / read - sys offset값
1. 버퍼(136)과 sfp(4)를 덮을 더미값을 넣는다.
2. read함수를 이용해서 bss영역에 "/bin/sh"문자열을 넣는다. 표준입력 0을 이용해서 client가 보낸 "/bin/sh"를 읽어서 bss영역에 담는다.
파이썬 코드 중 r.send(sh) 부분을 서버에서 입력받음 pppr을거쳐 다음으로
3. write함수를 이용해서 read_got에 담겨있는 read함수의 주소를 표준출력 1을 이용해서 client에 보낸다.
파이썬 코드 중 read_leak=u32(r.recv(4)) 부분에서 출력을 받아 변수에 저장한다. pppr을거쳐 다음으로
4. read함수는 이용해서 write_got에 system 함수의 주소를 넣는다. 표준입력 0을 이용해서 client가 보낸 real_sys를 읽어서 write_got에 담는다.
파이썬 코드 중 r.sendline(p32(real_sys))부분을 서버에서 입력받음 pppr을거쳐 다음으로
5. 마지막으로 write를 이용하지만 결국 write_got가 4번 과정에서 system주소로 overwriting되었기 때문에 system함수가 실행될 것이다.
최종
'CTF' 카테고리의 다른 글
[SSG] easy_linux_reversing (0) | 2018.05.02 |
---|---|
[Codegate 2017] babypwn (0) | 2018.02.06 |