ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • GrownUp write up
    System hacking training/pwnable.xyz 2020. 1. 2. 13:29

    GrownUp(50)
    prob

    바이너리안에 flag가 있다고 한다.

     

    file, checksec

    64bit바이너리고, NX와 Canary, Partial RELRO가 걸려있다.

     

    IDA-View main()

    18살인지 물어보고, 맞다면 이름을 입력 받고 Welcome "이름"의 형태로 출력을 해주는 바이너리다.

    또한 flag는 바이너리 내에 존재한다.

    (물론 서버에서 돌아가는 바이너리의 flag가 진짜 flag다.)

     

    flag

    이 문제의 핵심이라고 생각되는건 strcpy()함수의 특징이다.

     

    line 21에 보면 앞서 src에 132byte 동적 할당한 공간에 name에 대한 정보를 128byte입력받는다.

    그 후 strcpy()함수를 호출하여 usr에 복사를 한다.

     

    usr

    usr은 bss영역에 128byte할당되어있고, 0x6010E0 ~ 0x601160까지가 usr배열이다.

    usr의 일부 원소는 main()함수 line 11에서 setup()함수 호출에 의해 값이 세팅되는데

     

    IDA-View setup()

    usr[128] = 0x601168

    <usr+136> = '%s\n'

     

    위와 같이 세팅된다.

     

    gdb-view usr

    gdb로 확인해보면 0x601168에 '%s\n'문자열이 들어가 있고 0x601160에는 '%s\n'이 들어가있는 0x601168의 주소가 들어가있는 것을 확인할 수 있다.

     

    문제는 read()함수로 입력할 수 있는 128byte를 입력한 후 strcpy()함수가 호출되어 usr에 문자열이 복사될때 나타난다.

     

    'A' * 128 input -> strcpy(usr, buffer)

    A를 128개 넣고 확인한 결과 포맷스트링 '%s\n'의 주소를 갖고있던 <usr+128>의 위치에 NULL byte가 추가되어 엉뚱한 곳을 가리키고 있는 것을 볼 수 있는데

     

    strcpy()함수는 string복사를 한 뒤 NULL byte를 붙이기 때문에 이와같이 0x601168이 0x601100으로 바뀐것이다.

     

    이 상태에서 main()함수 line 26의 printf()함수를 호출하게 되면

     

    call printf(0x601100, 0x6010e0)

    원래의 형태 printf("%s\n", 0x6010e0)이 아닌 printf(0x601100, 0x6010e0)이 되어 호출되게 된다.

     

    현재까지 나온 분석의 결과는 다음과 같다.

    1. flag는 바이너리 내에 위치하며 PIE가 걸려있지 않기 때문에 고정주소(0x601080)를 갖는다.

    2. Name입력시 strcpy()에 의해 usr에 값이 복사되는데 strcpy()함수의 특성상 뒤에 NULL byte를 붙이며 끝나기 때문에 128byte 꽉 채운뒤 0x601168 -> 0x601100(사용자 입력범위)로 변조할 수 있다.

    3. 0x601100은 사용자 입력 범위안이고, 이후 printf()함수의 첫번째 인자로 들어간다.

    printf()함수는 int printf(const char *format, ...) 형태로 첫번째 인자에 formatstring이 위치한 곳을 가리키는 포인터가 들어간다.

     

    따라서 Format String Bug를 야기할 수 있다.

     

    FSB PoC

    간단한 payload를 작성하여 확인해보면

     

    Stack Leak

    다음과 같이 stack의 값이 leak이 되는것을 볼 수 있다.

     

    0x601100의 위치에 '%p...%p'가 저장되도록 32byte A를 input해줬고, 0x601168 -> 0x601100으로 세팅하기 위해 128byte를 빠짐없이 채워줬다.

     

    처음 여기서 생각이 들었던 공격루트는 원샷가젯으로 printf()함수의 got를 변조하여 쉘을 획득하는 것이였는데,

    바이너리안에 flag가 있다는 점과 libc base주소를 leak한 후 overwrite를 해야한다는 점, 그리고 NULL byte를 끝으로 인식하는 strcpy()함수의 특성 때문에 해당 공격을 시행할 수 없었다.

     

    따라서 다른 공격방법을 찾아야한다...

     

    compare 1byte

    코드로 다시 돌아와서

    main()함수의 line 16을 자세히 보면 (_BYTE)buf 가 'y' or 'Y'일때 if문의 조건을 만족시킨다.

    즉 1byte만 'y'이거나 'Y'이면 조건문을 만족한다는 것이다.

     

    이 점을 이용한다면

     

    PoC

    다음과 같이 'y'를 입력할 때 'B'를 15개 입력할 수 있고

     

    leak

    B가 stack에 올라와 %p에 의해 0x4242..의 형태로 출력되는 것을 확인할 수 있다.

     

    이 점을 이용하여 flag의 주소가 고정적이니 stack에 해당 주소를 올리고, %s로 해당 주소의 string을 뽑아내면 flag를 획득할 수 있다.

     

    payload

    ⚡ root@ubuntu  /mnt/hgfs/vm_shared/pwnable.xyz  python a.py
    [+] Opening connection to svc.pwnable.xyz on port 30004: Done
    [*] Switching to interactive mode
    Welcome 0x6010e0 0x7f83c469c8c0 (nil) 0x7f83c48c3500 0x8 0x10c46af3d0 0x1c18260 0x7979797979797979 FLAG{-------------------------} BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[*] Got EOF while reading in interactive
    반응형

    'System hacking training > pwnable.xyz' 카테고리의 다른 글

    xor write up  (0) 2020.02.05
    note write up  (1) 2020.01.10
    misalignment write up  (0) 2020.01.01
    add write up  (0) 2020.01.01
    sub write up  (0) 2019.12.31
Designed by Tistory.