How to deal with a bad char in a shellcode buffer overflow? - security

So I got recently interested in buffer overflow and many tutorials and recourses online have this CTF like attack where you need to read the content of a flag file (using cat for example).
So I started looking online for assembly examples of how to do this and I came accross sites like this or shell-storm where there are plenty of examples on how to do this.
So I generated my exploit and got this machine code (it basically executes a shell doing cat flag):
shellcode = b'\x31\xc0\x50\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x50\x68\x66\x6c\x61\x67\x89\xe1\x50\x51\x53\x89\xe1\x31\xc0\x83\xc0\x0b\xcd\x80'
The problem is that, thanks to stepping in with GDB to debug the problem, I noticed that my buffer doesn't get copied starting with \x0b towards the end of the shell code. I know the problem is there because if I change it to say \x3b then it works (with the rest of my exploits not copied here) even if it obviously crashes when it reaches the wrong value there but at least the whole buffer gets copied. Now doing some research it seems like \x0b is a "bad char" which can cause issues and should be avoided. Having said this I don't understand how:
All those online and even university tutorials use that shell code
for this exact task.
How to potentially fix this. Is it even possible without completely
change the assembly code?
I will add that I am on Ubuntu and trying to make this work on 64 bits.

One thing that's special about byte 0x0b is it's ASCII Vertical Tab, which is considered a whitespace character.
So I'm going to make a wild guess that the code you're exploiting looks something like
// Dangerous code, DO NOT USE
char buf[TOO_SMALL];
scanf("%s", buf);
since scanf("%s") is a commonly (mis)used input mechanism that stops when it hits whitespace. If so, then if your shellcode contains 0x0b or any other whitespace character, it will get truncated.
To your first question, as to "why do other tutorials use shellcode like this", they may be thinking instead of exploiting code like
// Dangerous code, DO NOT USE
char buf[TOO_SMALL];
gets(buf);
where gets() will not stop reading at 0x0b but only at newline 0x0a. Or maybe they are thinking of a buffer filled by strcpy() which will only stop at 0x00, or maybe a buffer filled by read() with a user-controlled size which will read the full amount of data no matter what bytes it contains. So the question of which characters are "bad" depends on what the vulnerable code actually does.
As to how to handle it, well, you need to modify your shellcode to use only instructions that don't contain any whitespace bytes. This sort of thing is more an art than a science; you have to know your instruction set well, and be creative in thinking about alternative instruction sequences to achieve the desired result. Sometimes you may be able to do it with minor tweaks; other times a wholesale rewrite may be needed. It really varies.
In this case, luckily the 0x0b is the only whitespace character in the whole code, and it appears in the instruction
83C00B add eax, 0x0b
Since eax was previously zeroed, the goal is to load it with the value 0xb which is the system call number of execve. When the "bad byte" appears as part of immediate data, it is usually not too hard to find another way to get that data to where it needs to go. (Life is harder when the bad byte is part of the opcode itself.) In this case, a simple solution is to take advantage of two's complement, and write instead
83E8F5 sub eax, -0x0b
The single byte -0x0b = 0xf5 gets sign-extended to 32 bits and used as the value to subtract, which leaves 0x0b in eax as desired. Of course there are lots of other ways, some of which may have smaller code size; I'll leave this to your ingenuity.

To find out the "bad char" for the shellcode is an important step to exploit an overflow vulneribility.
first, you have to figure out how many bits the target can be overflow (this field is also for the shellcode). if this zone is big enough and you can use all the "char"(google bad char from \x01 to \xff. \x00 is bad char) to act as shellcode send to target.
Then you can get find the Register to see what the char left.(if the zone is not big enough for all the chars you can send just some chars one time and repeat)
you can follow this https://netsec.ws/?p=180.

Related

Why do "lea..and..push" assembly codes frequently come up at the beginning of a function?

I realized when I am looking at some files through GDB, very frequently, there are these three lines of codes at the starting of the function
0x08048548 <+0>: lea ecx,[esp+0x4]
0x0804854c <+4>: and esp,0xfffffff0
0x0804854f <+7>: push DWORD PTR [ecx-0x4]
I usually ignored them because right after those three lines stack frame gets created which is how functions usually start.
Thank you.
This is aligning the stack pointer to a 16-byte boundary, because sometimes (for SSE) the CPU needs 16 byte alignment of data.
A good compiler will examine the call graph (figure out what calls what), and will decide that:
the function doesn't need stack alignment itself and doesn't call other functions that need stack alignment; and therefore no stack alignment is needed
all of the function's callers used an aligned stack, and therefore either:
the function only needs a fixed adjustment to re-establish the pre-existing alignment, like sub esp, 8 (which could be merged with any code that reserves stack space for local variables)
the data that actually needs 16 byte alignment can be given 16 byte alignment without aligning the stack itself
none of the above can be proven to be true, so the function has to assume "worst case" and enforce alignment itself (e.g. the instructions you've seen at the start of the function)
Of course for a good compiler, the last case (where the code you've shown is needed) is extremely rare.
However; most compilers can't be good because they're not able to see the whole program (if the program is split into multiple object files that are compiled separately, then the compiler can only see a fraction of the program at a time). They can't figure out much/any of the call graph, so the last case (where the code you've shown is needed) becomes very common. To solve this you need "link time code generation", but often people don't bother.
Note: For AVX2 you want 32 byte alignment, for AVX512 you want 64 byte alignment, and for some things (to avoid false sharing in heavily threaded code) you might want "cache line size alignment" (typically also 64 byte alignment). This makes the "examine call graph to determine what alignment is actually needed" algorithm a little more complicated than what I described.

How to tell compiler to pad a specific amount of bytes on every C function?

I'm trying to practice some live instrumentation and I saw there was a linker option -call-nop=prefix-nop, but it has some restriction as it only works with GOT function (I don't know how to force compiler to generate GOT function, and not sure if it's good idea for performance reason.) Also, -call-nop=* cannot pad more than 1 byte.
Ideally, I'd like to see a compiler option to pad any specific amount of bytes, and compiler will still perform all the normal function alignment.
Once I have this pad area, I can at run time to reuse these padding area to store some values or redirect the control flow.
P.S. I believe Linux kernel use similar trick to dynamically enable some software tracepoint.
-pg is intended for profile-guided optimization. The correct option for this is -fpatchable-function-entry
-fpatchable-function-entry=N[,M]
Generate N NOPs right at the beginning of each function, with the function entry point before the Mth NOP. If M is omitted, it defaults to 0 so the function entry points to the address just at the first NOP. The NOP instructions reserve extra space which can be used to patch in any desired instrumentation at run time, provided that the code segment is writable. The amount of space is controllable indirectly via the number of NOPs; the NOP instruction used corresponds to the instruction emitted by the internal GCC back-end interface gen_nop. This behavior is target-specific and may also depend on the architecture variant and/or other compilation options.
It'll insert N single-byte 0x90 NOPs and doesn't make use of multi-byte NOPs thus performance isn't as good as it should, but you probably don't care about that in this case so the option should work fine
I achieved this goal by implement my own mcount function in an assembly file and compile the code with -pg.

How do I do bcalls in hex?

So I have a TI-84 Plus C Silver Edition. I just started working on writing assembly programs on it using the opcodes. I found a good reference chart here, but was wondering how to do bcalls, specifically how to print a character to the screen. It seems as if the hex code for the call is 3 bytes long, but call takes in 2 bytes. So how do I call it?
Also, does anyone know the memory location programs are loaded into when they are run for my calculator? I haven't been able to find it yet.
Based on the definitions here: http://wikiti.brandonw.net/index.php?title=84PCSE:OS:Include_File , a "bcall" is a RST 28 instruction followed by the specific number of the bcall. So to print a character you would do (given that PutC is 44FB):
rst 28h
dw 44FBh
Presumably the character to print is in A register.
TI uses rst 28h for their bcall which translates to hexadecimal as EF. Bcalls are 2 bytes, but keep in mind that the Z80 and eZ80 are little-endian processors. So as mentioned earlier, _PutC is 44FB, so you would have to use the FB first, then the 44, making bcall(_PutC) equivalent to EFFB44.
I think the calc you are using has an eZ80. While the eZ80 is backwards compatible with the Z80 instruction set, the table to which you linked is not complete for the eZ80. If you are looking to get really wild, you can use the docs provided by Zilog here though I must warn you that if you are not fairly comfortable with Z80 Assembly, the reading material will be too dense.

Stack Overflow (Shellcoder's Handbook)

I'm currently following the erratas for the Shellcoder's Handbook (2nd edition).
The book is a little outdated but pretty good still. My problem right now is that I can't guess how long my payload needs to be I tried to follow every step (and run gdb with the same arguments) and I tried to guess where the buffer starts, but I don't know exactly. I'm kind of new to this too so it makes sense.
I have a vulnerable program with strcpy() and a buffer[512]. I want to make the stack overflow, so I run some A's with the program (as the Erratas for the Shellcoders Handbook). I want to find how long the payload needs to be (no ASLR) so in theory I just need to find where the buffer is.
Since I'm new I can't post an image, but the preferred output from the book has a full 4 row of 'A's (0x41414141), and mine is like this:
(gdb) x/20xw $esp - 532
0xbffff968 : 0x0000000 0xbfffffa0e 0x41414141 0x41414141
0xbffff968 0x41414141 0x41414141 0x00004141 0x0804834
What address is that? How I know where this buffer starts? I want to do this so I can keep working with the book. I realize that the buffer is somewhere in there because of the A's that I ran. But if I want to find how long the payload needs to be I need the point where it starts.
I'm not sure that you copied the output of gdb correctly. You used the command x/20xw, this says you'd like to examine 20 32-bit words of memory, displayed as hex. As such, each item of data displayed should consist of 0x followed by 8 characters. You have some some with only 7, and some with 9. I'll assume that you copied out the text by hand and made a few mistakes.
The address is the first item displayed on the line, so, for the first line the address is 0xbffff968, this is the address of the first byte on the line. From there you can figure out the address of every other byte on the line by counting.
Your second line looks a little messed up, you have the same address, and also you're missing the : character, again, I'll assume this is just a result of the copy. I would expect the address of the second line to be 0xbffff978.
If the buffer starts with the first word of 0x41414141 then this is at address 0xbffff970, though an easier way to figure out the address of a variable is just to ask gdb for the address of the variable, so, in your case, once gdb is stopped at a place where buffer is in scope:
(gdb) p &buffer
$1 = (char (*)[512]) 0xbffff970
Metasploit has a nice tool to assist with calculating the offset. It will generate a string that contains unique patterns. Using this pattern (and the value of EIP or whatever other location after using the pattern), you can see how big the buffer should be to write exactly into EIP or whatever other location.
Open the tools folder in the metasploit framework3 folder (I’m using a linux version of metasploit 3). You should find a tool called pattern_create.rb. Create a pattern of 5000 characters and write it into a file:
root#bt:/pentest/exploits/framework3/tools# ./pattern_create.rb
Usage: pattern_create.rb length [set a] [set b] [set c]
root#bt:/pentest/exploits/framework3/tools# ./pattern_create.rb 5000
Then just replace the A's with the output of the tool.
Run the application and wait until the application dies again, and take note of the contents of EIP or whatever other location.
Then use a second metasploit tool to calculate the exact length of the buffer before writing into EIP or whatever other location, feed it with the value of EIP or whatever other location(based on the pattern file) and length of the buffer :
root#bt:/pentest/exploits/framework3/tools# ./pattern_offset.rb 0x356b4234 5000
1094
root#bt:/pentest/exploits/framework3/tools#
That’s the buffer length needed to overwrite EIP or whatever other location.

How can I read a whole line of input in Assembly?

The only subroutine I know of capable of reading a user's alphabetical input is read_char, but how I want to be able to read the user's whole input of char no matter how long.
I have a vague notion that I have to make memory room to store the whole input or something? I'm really lost as I'm not certain if Assembly has a C++ equivalent of reading strings.
Thanks in advance.
Well, you should have a limit when reading input from the user, otherwise your program might not work properly anymore (see buffer overflow for more informations), so making room for the input and ensure the input won't exceed the buffer is very important.
Now, to get a string you have to call a dos interrupt, giving a pointer to your buffer and some other stuff. It will read until a carriage return is met.
But I think your prof wants you to read using his read_char, so (since this is homework), I'll give you a small advice: you have to do a loop and read chars until..

Resources