Creating a TCP Server to host ELF files - c

I've setup a TCP server with docker for a CTF competition I'm going to be hosting. The problem is, when I nc (netcat) into the running TCP Server on my localhost machine, the client does not receive the output of the executable.
I've never setup a TCP Server in the past, so this is new to me.
Bash Script
#!/bin/sh -e
exec tcpserver -v -P -R -H -l 0 0.0.0.0 1337 ./buff
Short C Script
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define FLAG ""
int main() {
int safe = 0xFACE0FF;
char name[32] = "";
fprintf(stderr, "So you wanna take my flag? ");
read(0, name, 0x32);
if (safe == 0xdec0de) {
fprintf(stderr, "Here's my flag: %s", FLAG);
} else {
puts("Goodluck dude!");
}
}
I want the client to read and send input. From the above C script.
The above bash script creates a successful TCP Server and listens for any incoming connections on port 1337, however when the client connects to the TCP Server, they can only pass input.

Check the man page for read(). The read function will wait until it's read the given number of bytes - in your case you specify 0x32 bytes (which is probably not what you expect). That's why it seems like it doesn't put output - it's waiting for 50 input characters before it continues.
You might want to consider getline() or something similar instead.
Also, check to make sure you use the same base on variable declaration as buffer sizes.

Related

Simple buffer overflow via xinetd

I'm trying to make a simple buffer overflow tutorial that runs the program below as a service on port 8000 via xinetd. Code was compiled using
gcc -o bof bof.c -fno-stack-protector
ubuntu has stack protection turned off as well.
Exploiting locally i.e
python -c ---snippet--- | ./bof
is successful and the hidden function was executed, displaying text file contents.
However, running it as a service and performing
python -c ---snippet--- | nc localhost 8000
returns nothing when exploiting. Am I missing something here?
#include <stdio.h>
void secret()
{
int c;
FILE *file;
file = fopen("congratulations.txt", "r");
if (file) {
while ((c= getc(file)) !=EOF)
putchar(c);
fclose(file);
}
void textdisplay()
{
char buffer[56];
scanf("%s", buffer);
printf("You entered: %s\n", buffer);
}
int main()
{
textdisplay();
return 0;
}
Output is buffered by default. To disable this you can do the following at the top of main:
setbuf(stdin, NULL);
This should fix your issue.
This is an issue that I am running into as well. Almost exactly the same.
However, here is one piece that I have found out that might be helpful to you. I believe the issue has something to do with xinetd not executing the binary as a terminal and having job control.
So what I did was to have xinetd do:
server = /usr/bin/python
server_args = /opt/shell.py
Then within the /opt/shell.py I had:
import pty
pty.spawn("/opt/oflow.elf")
/opt/oflow.elf being my overflowed binary
When I do this, I can actually send and receive data. Thats when I run the following command via netcat to try and overflow the service remotely:
**printf "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80AAAAAAAAAAAAAAAAAAAAAAAAABCDEFGHIJKLMNOPQ\x7c\xfc\xff\xbf" | nc 192.168.1.2 9000**
This does nothing. However, I test the local version and it works PERFECTLY. Works every time.
Not when its being wrapped in a python pty and xinetd.
When I run the xinetd pointing directly to /opt/oflow.elf, I get absolutely nothing back from netcat.
So that doesn't exactly answer your question but it should whittle it down for you.
UPDATED COMPLETE ANSWER:
I figured out why this wasnt working. No need to use python at all. After every printf statement you must also include:
fflush(stdout);
Otherwise, xinetd doesnt know to send the stdout.
You may also need to do this for stdin:
fflush(stdin);

Turn simple C program into server using netcat

One cool feature of netcat is how it can turn any command line program into a server. For example, on Unix systems we can make a simple date server by passing the date binary to netcat so that it's stdout is sent through the socket:
netcat -l -p 2020 -e date
Then we can invoke this service from another machine by simply issuing the command:
netcat <ip-address> 2020
Even a shell could be connected (/bin/sh), although I know this is highly unrecommended and has big security implications.
Similarly, I tried to make my own simple C program that both reads and writes from stdin and stdout:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char buffer[20];
printf("Please enter your name:\n");
fgets(buffer, 20, stdin);
printf("Hello there, %s\n", buffer);
return 0;
}
However, when I invoke the service from another terminal, there is no initial greeting; in fact the greeting is only printed after sending some information. For example:
user#computer:~$ netcat localhost 2020
User
Please enter your name:
Hello there, User
What do I need to do so that my greeting will be sent through the socket initially, then wait for input, then send the final message (just like I am invoking the binary directly)?
I know there may be better (and possibly more secure) approaches to implement such a system, but I am curious about the features of netcat, and why this does not work.
There's a high chance stdout is not line-buffered when writing to a non-terminal. Do an fflush(stdout) just after the printf.

RSA_generate_key() using prngd instead of /dev/random or /dev/urandom

I want to use RSA_generate_key() on HP-UX 11.11. But hp-ux 11.11 does not provide /dev/random or /dev/urandom, so I need to use openssl prngd.
Please let me know how to use it by default in C code. I have openssl installed and prngd is available.
$ ls /opt/openssl/prngd/prngd
/opt/openssl/prngd/prngd
Let me know if you need more information.
Noting that prngd uses the same interface that EGD does, checkout the instructions found here. A quote of interest is:
On systems without /dev/*random devices providing entropy from the kernel
Alternatively, the EGD-interface compatible daemon PRNGD can be used.
OpenSSL automatically queries EGD when entropy is requested via RAND_bytes() or the status is checked via RAND_status() for the first time, if the socket is located at /var/run/egd-pool, /dev/egd-pool or /etc/egd-pool.
So when you run prngd, run it as prngd /dev/egd-pool or one of the other alternatives
prngd simulates "/dev/random" and "/dev/urandom" over a network connection. It supports either a Unix stream-based domain socket ("/var/run/egd-pool") or (if configured to) or IP using TCP ports 708 or 4840 (default values---can be changed).
So, in using the Unix domain socket, it would look something like:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
int devrandom(void)
{
union
{
struct sockaddr sa;
struct sockaddr_un path;
} location;
int sock;
memset(&location,0,sizeof(location));
location.path.sun_family = AF_UNIX;
strcpy(location.path.sun_path,"/var/run/egd-pool");
sock = socket(AF_UNIX,SOCK_STREAM,0);
if (sock < 0)
return -1;
if (connect(sock,&location.sa,sizeof(struct sockaddr_un)) < 0)
return -1;
return sock;
}
This will return a file descriptor you can pass to read() in order to obtain the random data (note: this code is untested). A TCP/IP based connection is a bit more involved, requiring binding the socket to a local address and connecting to the remote address but there are plenty of examples on the Internet for that type of code.

How can I get the telnet result using C / Objective C?

Here is a telnet site:
telnet://202.85.101.136:8604/
It is from Hong Kong public library, can I write some programme to get the string / result from the telnet service, and send the request from C / Objective C? thz u.
Sure its possible. Telnet is a pretty simple protocol, you simply need to open a TCP socket and connect it to that IP and Port. When you first connect, the telnet server will send some negotiation requests using the binary protocol defined in RFC854, to which your client is expected to respond. Once negotiation is completed you communicate by simply sending and receiving ASCII data, normally a line at a time.
For a simple "get some data from a host" telnet sessions where you aren't trying to have a real interactive session, it sometimes works to simply accept all the servers negotiation settings to avoid implementing the whole negotiation protocol. To do this, just look for the server to send you several 3-byte commands in the format of: 0xFF 0xFD xx, which is basically the server telling you "I want you to use option X", just respond to this with 0xFF 0xFB xx, which basically is just you agreeing to whatever the server is asking for. Then when you get passed negotiations, you just have to receive lines with a socket read and send commands with a socket write.
If you have a telnet program already on your system, you can use it to do all the connection work for you. Here's a program for gnu/Linux that you can use as a starting point.
It uses popen to execute the system's telnet command. Then it just reads all data from the pipe (stdout if you just executed the telnet command by itself from the shell) and prints it. When there's no more data to read, it exits.
You can send data to the server by opening the pipe in rw mode instead of r and then writing like you would any other file. You could conditionally do stuff like scan your input for Username: and then send a username string too, for instance.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
const char *cmd = "telnet 202.85.101.136 8604";
char buffer[256];
FILE *pipe = popen(cmd, "r");
if( !pipe ) { perror("popen"); exit(-1); }
while( fgets(buffer, sizeof(buffer), pipe) != NULL &&
!feof(pipe) )
{
if( ferror(pipe) ) { perror("fgets"); break; }
/* Here you do whatever you want with the data. */
printf("%s", buffer);
}
pclose(pipe);
return 0;
}
If you're using Windows, this link explains the alternative to popen.
There's also a program called Expect that can help you automate stuff like this.

How to get IP address programmatically on Debian based system?

I'm trying to retrieve the IP Address of the local machine in my program. The Operating System is Ubuntu 8.10. I tried using gethostname() and gethostbyname() to retrieve the IP Address. The answer I received is 127.0.1.1. I learned that it seems to be a Debian thing:
The document linked here explained the idea.
The content of my /etc/hosts file is:
127.0.0.1 localhost
127.0.1.1 mymachine
In this case, is there any other way to programmatically (prefer C or C++) to get the IP Address without modifying the system file on the machine?
Here's some quick and dirty code that demonstrates SIOCGIFCONF :
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sock, i;
struct ifreq ifreqs[20];
struct ifconf ic;
ic.ifc_len = sizeof ifreqs;
ic.ifc_req = ifreqs;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
exit(1);
}
if (ioctl(sock, SIOCGIFCONF, &ic) < 0) {
perror("SIOCGIFCONF");
exit(1);
}
for (i = 0; i < ic.ifc_len/sizeof(struct ifreq); ++i)
printf("%s: %s\n", ifreqs[i].ifr_name,
inet_ntoa(((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr));
return 0;
}
I get the following output on my Linux machine.
lo: 127.0.0.1
br0: 192.168.0.42
dummy1: 10.0.0.2
So, as per Ken's point:
ip addr show scope global | grep inet | cut -d' ' -f6 | cut -d/ -f1
Shame that when the Debian gods made the "ip" command they didn't think to add a simple command to get just the ip address.
See "netdevice", through man netdevice or on the web.
SIOCGIFCONF can then be used to get an enumeration of all transport layer addresses.
Edit (on manpages): man is a very useful command on Linux (or other UNIX-like systems as well). It shows a brief description of most commands, library functions, programs, etc. Open a shell prompt and type man ls or man netdevice, and you'll see what I mean.
Edit (on general retrieving of IP): The easiest way, if you think the C way is too messy, is a simple shell script like (just from the top of my head):
ifconfig|grep 'inet addr'|awk '{print $2}'|sed 's/addr://g'
Edit (on the Brain solution): What he does is using the if_nameindex() function for finding all network device names, and then the SIOCFIFCONF ioctl on each of these names for finding their IP. As he says, it only lists one IP per device.
Take a look at the netdevice man page. Call SIOCGIFCONF to obtain a list of all the interfaces and their addresses.
Thanks all for the shares!
For a bash solution, this what I ended up going with:
#!/bin/bash
/sbin/ifconfig|fgrep 'inet addr:'|fgrep -v '127'|cut -d: -f2|awk '{print $1}'|head -n1
The head ensures the primary ip is returned, as multi homed and/or logical interfaces will also be returned without the head.
So if the script was located at /sbin/get_primary_ip, you could do stuff like:
foo=$(get_primary_ip)
ifconfig is deprecated and old. iproute2 is the new stack, use the ip command:
ip addr, and parse from there.

Resources