GDB with PEDA and Pwntools are two tools that we will be using extensively throughout the course. This section is designed to run through their basic use and to work out any possible kinks that might arise.
Throughout the section we will be using pre-built binaries in the build folder. From the base repository directory, please navigate as follows:
ubuntu@ubuntu-xenial:/vagrant$ cd lessons/3_intro_to_tools/
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools$ cd build/
There should be a couple of binaries already in the directory. They are standard ELF files that you can run.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ./1_sample
Hello, I am a sample program.
PEDA
PEDA (Python Exploit Development Assistance) is an extension to GDB that adds on a whole bunch of useful commands and quality of life improvements to the standard GDB experience. The provisioning script should have made the necessary additions to the GDB configuration so all you need to do to start it is launch GDB.
Let's walk through an example with the 1_sample binary.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ gdb ./1_sample
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./1_sample...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /vagrant/lessons/3_intro_to_tools/build/1_sample
Hello, I am a sample program.
[Inferior 1 (process 11030) exited normally]
Warning: not running or target is remote
gdb-peda$
The prompt should show gdb-peda. If it does not, something has gone wrong with the environment setup. To start off, let's break on main and explore what is offered by PEDA.
Notice that the default display is a made lot more informative than with the vanilla GDB. Other than making it a lot easier to step through programs and view the changes as they happen, PEDA provides a ton of other functionality as well. To view the full list of them, you can use the peda command.
gdb-peda$ peda
PEDA - Python Exploit Development Assistance for GDB
For latest update, check peda project page: https://github.com/longld/peda/
List of "peda" subcommands, type the subcommand to invoke it:
aslr -- Show/set ASLR setting of GDB
asmsearch -- Search for ASM instructions in memory
assemble -- On the fly assemble and execute instructions using NASM
checksec -- Check for various security options of binary
cmpmem -- Compare content of a memory region with a file
context -- Display various information of current execution context
context_code -- Display nearby disassembly at $PC of current execution context
context_register -- Display register information of current execution context
context_stack -- Display stack of current execution context
crashdump -- Display crashdump info and save to file
deactive -- Bypass a function by ignoring its execution (eg sleep/alarm)
distance -- Calculate distance between two addresses
dumpargs -- Display arguments passed to a function when stopped at a call instruction
tracecall -- Trace function calls made by the program
... snip ...
traceinst -- Trace specific instructions executed by the program
unptrace -- Disable anti-ptrace detection
utils -- Miscelaneous utilities from utils module
vmmap -- Get virtual mapping address ranges of section(s) in debugged process
waitfor -- Try to attach to new forked process; mimic "attach -waitfor"
xinfo -- Display detail information of address/registers
xormem -- XOR a memory region with a key
xprint -- Extra support to GDB's print command
xrefs -- Search for all call/data access references to a function/variable
xuntil -- Continue execution until an address or function
Type "help" followed by subcommand for full documentation.
gdb-peda$
We will go through a few of the interesting commands.
checksec
The checksec command lists the protections that are enabled for the binary. This is useful when figuring out how to craft your exploit.
Often, calculating offsets from addresses is required when crafting your payload in an exploit. This command makes it easy to find the distance between two addresses.
gdb-peda$ distance 0x7fffffffe4f0 0x7fffffffe528
From 0x7fffffffe4f0 to 0x7fffffffe528: 56 bytes, 14 dwords
gdb-peda$
elfsymbol
If you ever needed to get the address for certain symbols in a binary (if you are lucky and it is not stripped), you can use the elfsymbol command.
The pattern generator is one of the features of PEDA I most use. What it does is generate a De Brujin Sequence of a specified length. A De Brujin Sequence is a sequence that has unique n-length subsequences at any of its points. In our case, we are interested in unique 4 length subsequences since we will be dealing with 32 bit registers. This is especially useful for finding offsets at which data gets written into registers.
Imagine that we have triggered a buffer overflow and find that the instruction pointer crashes on the address 0x48414132 ('2AAH' in ASCII). We can figure out the exact offset of our data to place our address to redirect code execution to.
gdb-peda$ pattern offset 0x48414132
1212236082 found at offset: 60
gdb-peda$ pattern offset 2AAH
2AAH found at offset: 60
gdb-peda$
procinfo
This command parses information from the /proc/pid/x directory and presents it to you.
What is important to glean from the listing above is the permissions flags of each of the segments. Often when developing your exploit, you will need to place some data somewhere. This data can be arguments to functions expecting a string pointer or even shellcode. What is required is that the segment that is being written to is marked writable.
Additionally, if you have a pointer from a memory leak and want to figure out where exactly the pointer is pointing to, you can drill down specifically on that address.
gdb-peda$ vmmap 0x00601000
Start End Perm Name
0x00601000 0x00602000 rw-p
/vagrant/lessons/3_intro_to_tools/build/1_sample
gdb-peda$
find aka searchmem
The find command is an alias for the searchmem peda command. It searches memory for a given pattern. It is particularly useful to figure out where data is or how it flows in a process.
For example, something that is often sought for is the string "/bin/sh". Perhaps it lays in memory somewhere. We can use find to look for it.
gdb-peda$ find /bin/sh
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0x7ffff7b9a177 --> 0x68732f6e69622f ('/bin/sh')
gdb-peda$
Pwntools
Pwntools is a Python library that provides a framework for writing exploits. Typically, it is used heavily in CTFs. There are a ton of useful functions provided by Pwntools but I will briefly describe the process I personally use.
Using Pwntools
There are three ways you can use Pwntools:
Interactively through the python/iPython consoles
In a python script
Pwntools command line tools
Interactively through the Console
Often, you want to try things out before actually writing an actual script when developing your exploit. The iPython console is a great way to explore the Pwntools API. For convenience, we will import everything in the pwn package to the global namespace.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ipython
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: from pwn import *
In [2]:
iPython provides tab completion and a built-in system to look up documentation in docstrings. For example, if we want to look at what the p32 function does, we can look it up with the ? sigil.
In [4]: p32?
Signature: p32(*a, **kw)
Docstring:
p32(number, sign, endian, ...) -> str
Packs an 32-bit integer
Arguments:
number (int): Number to convert
endianness (str): Endianness of the converted integer ("little"/"big")
sign (str): Signedness of the converted integer ("unsigned"/"signed")
kwargs (dict): Arguments passed to context.local(), such as
``endian`` or ``signed``.
Returns:
The packed number as a string
File: /usr/local/lib/python2.7/dist-packages/pwnlib/context/__init__.py
Type: function
In [5]: p32(0x41424344)
Out[5]: 'DCBA'
In [6]:
In a Python Script
I like to begin with the following template when starting a new exploit.
#!/usr/bin/python
from pwn import *
def main():
pass
if __name__ == '__main__':
main()
Running the script is as simple as calling python on it. Try running this script:
#!/usr/bin/python
from pwn import *
def main():
p = process("/bin/sh")
p.interactive()
if __name__ == '__main__':
main()
Running the script:
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ python 2_shellsample.py
[+] Starting local process '/bin/sh': Done
[*] Switching to interactive mode
$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),110(lxd)
$
Pwntools Command Line Tools
Pwntools installs the pwn python script in /usr/local/bin. It provides frontends to useful features of the library. To get a list of all available frontends, you can execute pwn -h.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ pwn -h
usage: pwn [-h]
{asm,checksec,constgrep,cyclic,disasm,elfdiff,elfpatch,errno,hex,phd,pwnstrip,scramble,shellcraft,unhex,update}
...
Pwntools Command-line Interface
positional arguments:
{asm,checksec,constgrep,cyclic,disasm,elfdiff,elfpatch,errno,hex,phd,pwnstrip,scramble,shellcraft,unhex,update}
asm Assemble shellcode into bytes
checksec Check binary security settings
constgrep Looking up constants from header files. Example:
constgrep -c freebsd -m ^PROT_ '3 + 4'
cyclic Cyclic pattern creator/finder
disasm Disassemble bytes into text format
elfdiff Compare two ELF files
elfpatch Patch an ELF file
errno Prints out error messages
hex Hex-encodes data provided on the command line or stdin
phd Pwnlib HexDump
pwnstrip Strip binaries for CTF usage
scramble Shellcode encoder
shellcraft Microwave shellcode -- Easy, fast and delicious
unhex Decodes hex-encoded data provided on the command line
or via stdin.
update Check for pwntools updates
optional arguments:
-h, --help show this help message and exit
You can investigate the available options at your own time. Take a look at the documentation for a more detailed description of each of them.
Interacting with Target Binaries
Your target might expose itself through different vectors. Today we will focus on attacking remotely running binaries that you can connect to over the network. First, let's see how we might interact with a local copy of a binary that accepts input on stdin and returns output on stdout.
Local Copy of Binary
To begin with, we will look at the 2_interactive binary:
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ./2_interactive
Welcome to the Super Secure Shell
Password: HelloWorld?
Incorrect password!
For completeness sake, here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void give_shell() {
system("/bin/sh");
}
int main() {
// Disable buffering on stdin and stdout to make network connections better.
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char * password = "TheRealPassword";
char user_password[200];
puts("Welcome to the Super Secure Shell");
printf("Password: ");
scanf("%199s", user_password);
if (strcmp(password, user_password) == 0) {
puts("Correct password!");
give_shell();
}
else {
puts("Incorrect password!");
}
}
The point of the program is to check the user input against a hardcoded password. If it matches, then an interactive shell is spawned.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ./2_interactive
Welcome to the Super Secure Shell
Password: TheRealPassword
Correct password!
$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),110(lxd),999(docker)
$ exit
Now that we know how to craft the input, we can write our sample exploit using Pwntools.
#!/usr/bin/python
from pwn import *
def main():
# Start a local process
p = process("../build/2_interactive")
# Get rid of the prompt
data1 = p.recvrepeat(0.2)
log.info("Got data: %s" % data1)
# Send the password
p.sendline("TheRealPassword")
# Check for success or failure
data2 = p.recvline()
log.info("Got data: %s" % data2)
if "Correct" in data2:
# Hand interaction over to the user if successful
log.success("Success! Enjoy your shell!")
p.interactive()
else:
log.failure("Password was incorrect.")
if __name__ == "__main__":
main()
Take some time to go through the code and understand what it does. Take note of the process("../build/2_interactive") line. It starts a new process and allows you to treat the object like a socket. Run the script and verify it works:
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ python 3_interactive.py
[+] Starting local process '../build/2_interactive': Done
[*] Got data: Welcome to the Super Secure Shell
Password:
[*] Got data: Correct password!
[+] Success! Enjoy your shell!
[*] Switching to interactive mode
$ ls -la
total 20
drwxrwxr-x 1 ubuntu ubuntu 4096 Jan 11 12:28 .
drwxrwxr-x 1 ubuntu ubuntu 4096 Jan 11 12:04 ..
-rw-rw-r-- 1 ubuntu ubuntu 98 Jan 10 11:36 1_template.py
-rw-rw-r-- 1 ubuntu ubuntu 136 Jan 10 11:56 2_shellsample.py
-rw-rw-r-- 1 ubuntu ubuntu 570 Jan 11 12:28 3_interactive.py
$
[*] Interrupted
[*] Stopped program '../build/2_interactive'
Simulating a Networked Application Locally
It is very easy to turn a console-based application into a networked one and there are multiple ways to do it. The exercises that come later in the docker containers use xinetd, a server daemon, to listen for network requests and then launch the binary to serve these requests. For now, we can use socat to do the same thing.
First, we will start a new screen session so that we can background our socat terminal.
It should hang there. Now return to your original bash session by holding down the following key sequence: CTRL-A-D. If you run the command screen -ls you should see that the socat screen session is in the background.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ screen -ls
There is a screen on:
5371.pts-0.ubuntu-xenial (01/11/2017 01:04:01 PM) (Detached)
1 Socket in /var/run/screen/S-ubuntu.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$
To verify that the listener is indeed listening on port 1330, we can run netcat.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ nc localhost 1330
Welcome to the Super Secure Shell
Password: Hello
Incorrect password!
Now, here comes the magic. To modify the first script we had to work with local binaries, we may simply comment out the process() line and replace the line with remote("localhost", 1330).
#!/usr/bin/python
from pwn import *
def main():
# Start a local process
#p = process("../build/2_interactive")
p = remote("localhost", 1330)
# Get rid of the prompt
data1 = p.recvrepeat(0.2)
log.info("Got data: %s" % data1)
# Send the password
p.sendline("TheRealPassword")
# Check for success or failure
data2 = p.recvline()
log.info("Got data: %s" % data2)
if "Correct" in data2:
# Hand interaction over to the user if successful
log.success("Success! Enjoy your shell!")
p.interactive()
else:
log.failure("Password was incorrect.")
if __name__ == "__main__":
main()
Now, if we run this it should give us our shell.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ python 4_networked.py
[+] Opening connection to localhost on port 1330: Done
[*] Got data: Welcome to the Super Secure Shell
Password:
[*] Got data: Correct password!
[+] Success! Enjoy your shell!
[*] Switching to interactive mode
$ ls -la
total 40
drwxrwxr-x 1 ubuntu ubuntu 4096 Jan 10 12:06 .
drwxrwxr-x 1 ubuntu ubuntu 4096 Jan 11 13:21 ..
-rwxrwxr-x 1 ubuntu ubuntu 8608 Jan 9 21:00 1_sample
-rwxrwxr-x 1 ubuntu ubuntu 9064 Jan 9 21:00 2_interactive
-rw------- 1 ubuntu ubuntu 501 Jan 10 12:06 .gdb_history
-rw-rw-r-- 1 ubuntu ubuntu 12 Jan 10 12:02 peda-session-1_sample.txt
$
[*] Closed connection to localhost port 1330
Debugging with GDB
Pwntools does provide GDB functionality but we will be taking a more manual approach since that is the way I am used to doing it. If you are interested in using this functionality, you can view the documentation here.
We will be using the 3_reversing binary to walkthrough this section. First, lets run it vanilla.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ./3_reversing
Name: This is a Name
Token: AAAA
Submitted Name: This is a Name
Submitted Token: 0x41414141
Incorrect credentials.
To gain a deeper insight into what is going on, we can use ltrace to investigate.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/build$ ltrace ./3_reversing
__libc_start_main(0x4007b1, 1, 0x7ffed30e1418, 0x4008f0 <unfinished ...>
setvbuf(0x7f661ca358e0, 0, 2, 0) = 0
setvbuf(0x7f661ca36620, 0, 2, 0) = 0
printf("Name: "Name: ) = 6
read(0This is a Name
, "This is a Name\n", 63) = 15
printf("Token: "Token: ) = 7
read(0AAAA
, "AAAA", 4) = 4
printf("Submitted Name: %s\n", "This is a Name\n"Submitted Name: This is a Name
) = 32
printf("Submitted Token: 0x%x\n", 0x41414141Submitted Token: 0x41414141
) = 28
strcmp("Santo & Johnny", "This is a Name\n") = -1
puts("Incorrect credentials."Incorrect credentials.
) = 23
+++ exited (status 0) +++
Using the following script, we can print the process id before the interaction with the program happens.
#!/usr/bin/python
from pwn import *
def main():
# Start a new process
p = process("../build/3_reversing")
# Name and Token
name = "Test Name".ljust(63, "\x00")
token = 0x41414141
# Print pid
raw_input(str(p.proc.pid))
# Send name and token
p.send(name)
p.send(p32(token))
# Start an interactive session
p.interactive()
if __name__ == "__main__":
main()
First, start another ssh session and run the script. Note the process id that gets printed. Also note the use of p32() to pack integers into little endian strings.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ python 5_gdb.py
[+] Starting local process '../build/3_reversing': Done
5652
Return to the original bash shell and run GDB as root. Now, we can attach to the process.
ubuntu@ubuntu-xenial:/vagrant/lessons/3_intro_to_tools/scripts$ sudo gdb
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
gdb-peda$ attach 5652
Attaching to process 5652
Reading symbols from /vagrant/lessons/3_intro_to_tools/build/3_reversing...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
[----------------------------------registers-----------------------------------]
RAX: 0xfffffffffffffe00
RBX: 0x0
RCX: 0x7f2156e17680 (<__read_nocancel+7>: cmp rax,0xfffffffffffff001)
RDX: 0x3f ('?')
RSI: 0x7ffc16545500 --> 0x0
RDI: 0x0
RBP: 0x7ffc16545550 --> 0x4008f0 (<__libc_csu_init>: push r15)
RSP: 0x7ffc165454e8 --> 0x400844 (<main+147>: mov edi,0x40098a)
RIP: 0x7f2156e17680 (<__read_nocancel+7>: cmp rax,0xfffffffffffff001)
R8 : 0x7f2157304700 (0x00007f2157304700)
R9 : 0x6
R10: 0x37b
R11: 0x246
R12: 0x400680 (<_start>: xor ebp,ebp)
R13: 0x7ffc16545630 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x7f2156e17677 <read+7>: jne 0x7f2156e17689 <read+25>
0x7f2156e17679 <__read_nocancel>: mov eax,0x0
0x7f2156e1767e <__read_nocancel+5>: syscall
=> 0x7f2156e17680 <__read_nocancel+7>: cmp rax,0xfffffffffffff001
0x7f2156e17686 <__read_nocancel+13>: jae 0x7f2156e176b9 <read+73>
0x7f2156e17688 <__read_nocancel+15>: ret
0x7f2156e17689 <read+25>: sub rsp,0x8
0x7f2156e1768d <read+29>: call 0x7f2156e354e0 <__libc_enable_asynccancel>
[------------------------------------stack-------------------------------------]
0000| 0x7ffc165454e8 --> 0x400844 (<main+147>: mov edi,0x40098a)
0008| 0x7ffc165454f0 --> 0x0
0016| 0x7ffc165454f8 --> 0x4141414100000000 ('')
0024| 0x7ffc16545500 --> 0x0
0032| 0x7ffc16545508 --> 0x0
0040| 0x7ffc16545510 --> 0x0
0048| 0x7ffc16545518 --> 0x0
0056| 0x7ffc16545520 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00007f2156e17680 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
gdb-peda$
At this point, the program is paused somewhere in libc. We can setup our breakpoints. Let's assume that we have done some preliminary reverse engineering and have discovered that the input gets passed to the check_creds(). Here's the disassembly of the function.
gdb-peda$ disas check_creds
Dump of assembler code for function check_creds:
0x0000000000400776 <+0>: push rbp
0x0000000000400777 <+1>: mov rbp,rsp
0x000000000040077a <+4>: sub rsp,0x10
0x000000000040077e <+8>: mov QWORD PTR [rbp-0x8],rdi
0x0000000000400782 <+12>: mov DWORD PTR [rbp-0xc],esi
0x0000000000400785 <+15>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400789 <+19>: mov rsi,rax
0x000000000040078c <+22>: mov edi,0x400974
0x0000000000400791 <+27>: call 0x400650 <strcmp@plt>
0x0000000000400796 <+32>: test eax,eax
0x0000000000400798 <+34>: je 0x4007aa <check_creds+52>
0x000000000040079a <+36>: cmp DWORD PTR [rbp-0xc],0xdeadc0de
0x00000000004007a1 <+43>: jne 0x4007aa <check_creds+52>
0x00000000004007a3 <+45>: mov eax,0x0
0x00000000004007a8 <+50>: jmp 0x4007af <check_creds+57>
0x00000000004007aa <+52>: mov eax,0x1
0x00000000004007af <+57>: leave
0x00000000004007b0 <+58>: ret
End of assembler dump.
gdb-peda$
Let's place some breakpoints on the function and step through the execution to discover what inputs we need to supply to pass the check.
gdb-peda$ br check_creds
Breakpoint 1 at 0x40077a
gdb-peda$ c
Continuing.
gdb-peda$
Back on the terminal with the script running, press enter to trigger the data sending. On the gdb terminal, the debugger should have broken. Continue on with the standard gdb debugging process to obtain the values.
Exercises
Please attempt the exercises in this section on your own before looking at the solution.
Ex 3.1: Getting the Right Name and Token
Continuing on from where we left off in the guided portion, please find the right values for the name and token and modify the exploit code such that a shell is obtained.
Solution script can be found here.
Ex 3.2: Launching the Attack Against a Remote Target
Please find the flag file on an instance of the service running at 127.0.0.1:1900.