I have a CTF challenge in which i've got a simple code vulnerable to buffer over flow (via strcpy) which looks like:
#include <stdio.h>
#include <string.h>
int display(char *text)
{
char buffer[20];
strcpy(buffer, texte);
printf("%s\n",buffer);
}
int main(int argc, char ** argv)
{
char forbidden[]={0x00, 0x80, 0x89, 0xe1, 0x89};
int i,j;
if (argc!=2)
{
printf("Usage: %s <text>\n", argv[0]);
return 1;
}
for(i=0;argv[1][i];i++)
{
for(j=0;forbidden[j];j++)
{
if(argv[1][i] == forbidden[j])
{
printf("Shellcode detected!\n");
return 1;
}
}
}
display(argv[1]);
return 0;
}
I managed to debug via GDB and see the addresses and instructions, I took full control of the memory, so I managed to corrupt the memory and inject my own shellcode, and change the return address to that block which runs my code.
But what bothers me, is the code check forbidden characters that I need to use to execute a \bin\cat, which really relies on 0x80 (OpCode of system call), i used shellcode generator such as masterccc.github. But it nevers provide me a shellcode without those forbidden characters, i tried as well an encoder (change shellcode instructions but have the same semantic) but no way.
I just want to know if i am in right path, and i have to execute shellcode and bypass this verification, or it's wrong path ? give me some Hint please.
I'm working on x86 32-bit.
There are other ways to get a shell ;)
You should probably check what is a ROP chain
If you still want to use a shellcode (and this is probably the easiest way), you could also inject it in an env variable instead of the argv[1] and use
jmp ADDRESS_OF_THE_SHELLCODE_IN_ENV
in argv[1]. It won't trigger the forbidden characters.
Have fun with the CTF!
Related
I am currently tackling on an assignment, where I need to upload exploit.c and target.c onto a ubuntu server, and successfully achieve a buffer overflow attack with exploit onto target. I was provided a shellcode. Now, target.c is not to be altered, just exploit.c. I had to use GDB on exploit.c to force an external breakpoint on foo() from target.c, to figure out the return addresses using info frame.
I was provided with the working shellcode, and minimal instructions.
I am pretty sure I was able to successfully pull the return addresses, but my issue is that I cannot figure out what code to put into exploit.c to have it successfully perform a buffer overflow attack. I was also instructed that one of the return addresses must be input into the exploit code for it to function properly.
I understand that the exploit is trying to call back to the return address, to then push itself into the buffer, so I can obtain access to the shell.
Here is exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
// replace this define environment to have the correct path of your own target code
#define TARGET "/*******************"
int main(void)
{
char *args[3];
char *env[2];
char *tmp = NULL;
// Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code
int buffSize = 1000;
char buff[buffSize];
// Intialize buffer elements to 0x01
int i;
for (i=0; i < buffSize; i++) buff[i] = 0x01;
// write your code below to fill the 22 bytes shellcode into the buff variable, and
// at the correct location overwrite the return address correctly in order to achieve stack overflow
// Your own code starts here:
strcpy (buff[buffSize-22], shellcode);
// Your code ends here.
// prepare command line input to execute target code
args[0] = TARGET; // you must have already compiled and generated the target executable code first
args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string)
args[2] = NULL;
env[0] = "FOO=bar";
env[1] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Here is the target.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char* arg)
{
char localBuf[240];
short len = 240;
float var1=2.4;
int *ptr = NULL;
strcpy(localBuf, arg);
printf("foo() finishes normally.\n");
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0; tv.tv_usec=0;
FD_ZERO(&read_fd); FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target: argc != 2\n");
exit(EXIT_FAILURE);
}
printf("Press any key to call foo function...\n");
while(!kbhit())
;
foo(argv[1]);
return 0;
}
I compiled both target and exploit. Then I ran GDB on exploit, and formed a breakpoint using "break target.c:10". Using Info Frame I was able to obtain the return addresses.
I used strcpy, because it is essentially the only line of code we were taught for this section involving overflow attacks, even though it clearly states in the document "Fill the shell executable code (in the string array shellcode[]) byte-by-
byte into the buff for your modified return address to execute, do not
use strcpy() because shellcode[] is not an ASCII string (and not
copying NULL byte, too)."
Exploit compiles fine, and it runs fine, but it does not give me access to a shell. I was instructed that I would know if it worked, if I was presented with two dollar signs ($$) instead of one ($).
I am a network engineer, and I am not entirely savvy with C, or attacking vulnerabilities in programs, any help would be appreciated. The entire lesson revolves around "stack overflow", but this assignment is called "buffer overflow attack".
I'm trying to call the oopsIGotToTheBadFunction by changing the return address via the user input in goodFunctionUserInput.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int oopsIGotToTheBadFunction(void)
{
printf("Gotcha!\n");
exit(0);
}
int goodFunctionUserInput(void)
{
char buf[12];
gets(buf);
return(1);
}
int main(void)
{
goodFunctionUserInput();
printf("Overflow failed\n");
return(1);
}
/**
> gcc isThisGood.c
> a.out
hello
Overflow failed
*/
I've tried loading the buffer with 0123456789012345 but not sure what to put for the rest of it to get the address. The address is 0x1000008fc.
Any insights or comments would be helpful.
I'm going to give this the benefit of the doubt and presume this is an exercise intended to learn about the stack (perhaps homework) and not learning how to do anything malicious.
Consider where the return address of goodFunctionUserInput is on the stack and what would happen if you changed it. You may wish to check the disassembly to see how much space on the stack the compiler made for goodFunctionUserInput and where exactly buf is. When you figure out how long a string to enter, consider the endianness of the machine and what that means for the address you want to overwrite into the return address of goodFunctionUserInput. Worrying about what sorts of awful things this does to the stack isn't important here as your function you want to call simply calls exit.
I have installed the linux distro named DVL (damn vulnerable linux), and I'm exercising with buffer overflow exploits.
I wrote two virtually identical programs which are vulnerable to bof:
//bof_n.c
#include <stdio.h>
void bof() {
printf("BOF");
}
void foo(char* argv) {
char buf[10];
strcpy(buf, argv);
prinf("foo");
}
int main(int argc, char* argv[]) {
if (argc >= 1) {
foo(argv[1]);
}
return 0;
}
and
//bof.c
#include <stdio.h>
void bof() {
printf("BOF!\n");//this is the only change
}
void foo(char* argv) {
char buf[10];
strcpy(buf, argv);
prinf("foo");
}
int main(int argc, char* argv[]) {
if (argc >= 1) {
foo(argv[1]);
}
return 0;
}
After that I compiled both of them, and I obtained the bof() function address in both cases (e.g., objdump -d bof.o | grep bof). Let's name such an address ADDR which is on 4 byte.
I also found that if I write 32 byte in the buf variable, the EIP register is completely overwritten (I cannot copy here the output of gdb since it is on a virtual machine).
Now, if I do:
./bof `perl -e 'print "\x90"x28 . "ADDR"'`
I get:
fooBOF!
Segmentation fault
Instead if I try the same approach but using bof_n, I only get the "Segmentation fault" message.
Therefore I tried to increment the number of time ADDR value is repeated, and I found that if it is being repeated for at least 350 times, I get the wanted result. But instead of having the output above exactly, I get a long list of "BOF" messages one after the other. I tried to obtain just one "BOF" message, but apparently I cannot do that (I got or zero, or a long list of them).
Why this is happening? Any idea?
I'm using DVL with gcc 3.4.6
What's your goal?
You should really be using a debugger for this, try the GDB Debugger or gdb. With it you can see the memory/registers/stack and disassembly of whats currently going on in the system.
I'd guess that in the first function, the string being only 3 characters in length, gets optimized to \x42\x4f\x46\x00, so the disassembly may be slightly different.
The C source is pretty much irrelevant, you'll need to either disassemble or fuzz both binaries to find appropriate size for both NOP sleds.
I found out the solution. The issue was about the printing of the message and not the buffer overflow exploit itself.
In fact the register eip was being correctly overwritten also in the bof_n example, and the program flow was being correctly redirected in the bof() function. The problem was that, apparently, the stdout were not flushed out before the Segmentation fault and hence no message was being shown.
Instead, using fprintf(stderr, "BOF");, I finally get the "BOF" message.
#include <WhatHere?>
#include <WhatHere?>
#include <WhatHere?>
int main(int argc, char **argv) {
char command[50] = "echo ";
strcat(command,argv[1]); // concatenate the input so that the final command is "echo <input>"
system(command); // call the system() function to print the input
return 0; // denote that the program has finished executing successfully
}
Can we get a remote access by running this code ? I know it is possible but please help me patch it up.
Assuming that you're worried about the potential buffer overflow, you could fix it like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv) {
char *command;
if (argc != 2) {
fprintf (stderr, "Wrong number of arguments\n");
return 1;
}
if ((command = malloc (strlen (argv[1]) + 6)) == NULL) {
fprintf (stderr, "Could not allocate memory\n");
return 1;
}
strcpy (command, "echo ");
strcat(command,argv[1]);
system(command);
free (command);
return 0;
}
This makes enough room for "echo " (5), argv[1] (string length) and the null terminator (1).
It's still potentially dangerous allowing user-specified stuff to be run but at least you won't get buffer overflows any more.
Paxdiablo gave a good solution to your buffer overflow problem, but that's really the least of your problems here. Your big issue is that you are blindly using input from the user without inspecting it first.
For example, running your program like:
./your_app "\"goodbye data\" && rm -rf /"
would end in disaster, even if you program had no buffer overflow problems. An attacker could just as easily pass in an entire shell script that did all sorts of nasty things, all they would have to do is re-write it to fit in a single line.
You need to inspect incoming user input before you pass it to system() and make sure that it looks like what you are expecting. Better yet, avoid using system() with user input entirely and instead use safer methods to do what you need (in your example, you can replace your call to system("echo ...") with printf()). If you absolutely must pass user input to system(), consider running your app in a restricted environment like a chroot jail to at least make it more difficult to do anything nasty.
#include <stdio.h>
int main(int argc, char** argv)
{
void (*p) (void);
/* this obviously won't work, but what string could I put in
here (if anything) to make this execute something meaningful?
Does any OS allow instructions to be read from
the stack rather than text area of the process image? */
char *c = "void f() { printf(\"Hello, world!\"); }";
p = ( void (*)() )c;
p();
return 0;
}
Sort of, but not really, there is no eval() in c, like in many scripting languages.
However, what you are describing is sort of like a Buffer Overflow exploit.
Where, you use a string to write "code" (not c syntax, but machine code) into the address space after the buffer. Here's a nice little tutorial of the topic.
Don't use this information to write a virus :(
You could use libtcc to compile and run C source code:
const char *code = "int main(int argc, char**argv) { printf(\"Hello, world!\"); return 0; }";
TCCState *tcc = tcc_new();
if (tcc_compile_string(tcc, code))
{
// an error occurred compiling the string (syntax errors perhaps?)
}
int argc = 1;
char *argv[] = { "test" };
int result = tcc_run (tcc, argc, argv);
// result should be the return value of the compiled "main" function.
// be sure to delete the memory used by libtcc
tcc_delete(tcc);
A coouple of issues:
You can only compile libtcc on a supported architecture.
You need to have a main function.
Sure it is possible. Buffer Overflow exploits use it.
See Shellcode for what kind of strings you can place.
Basically what you can do it put machine code on the stack and jump to the address. This will cause execution (if the OS/machine allows it, see NX bit).
You could perhaps even try to do a memcpy from some function address onto a string on the stack and then try jumping to the address on the stack.