Turn simple C program into server using netcat - c

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.

Related

fgets causes C program to hang when run from bash on Windows, but works correctly when run from CMD or WSL

I'm following a 'Build your own Lisp' tutorial to teach myself C, and came across some strange behavior related to fgets. Here is a link to the Chapter I am working on: http://www.buildyourownlisp.com/chapter4_interactive_prompt#an_interactive_prompt
The code is a simple base for what will eventually be the REPL. It just prints some info, and then starts a loop that gets and prints user input.
#include <stdio.h>
static char input[2048];
int main(int argc, char** argv) {
puts("Brenlisp Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
while (1) {
fputs("brenlisp> ", stdout);
fgets(input, 2048, stdin);
fputs(input, stdout);
}
return 0;
}
When I ran the executable from a Bash terminal (Windows 10), the program started but did not print anything to console, nor did it accept/print user input.
bschw#DESKTOP-92VUB1F MINGW64 ~/Projects/brenlisp
$ ./prompt.exe
However, when I ran the executable from CMD, the prompt performed as expected:
C:\Users\bschw\Projects\brenlisp>prompt.exe
BrenLisp Version 0.0.0.0.1
Press Ctrl+c to Exit
brenlisp> works fine
works fine
brenlisp> works fine
brenlisp> ^C
C:\Users\bschw\Projects\brenlisp>
Another curious thing is that when I run the program on WSL, it doesn't print the "^C" string to the console before exiting:
bschw#DESKTOP-92VUB1F:/mnt/c/Users/bschw/Projects/brenlisp$ ./prompt.exe
BrenLisp Version 0.0.0.0.1
Press Ctrl+c to Exit
brenlisp> works
works
brenlisp> works
brenlisp> bschw#DESKTOP-92VUB1F:/mnt/c/Users/bschw/Projects/brenlisp$
Why are these programs behaving differently depending on which shell they're being run from? How could I get the program to work properly on Bash?
In many implementations, the C Standard Library buffers output in internal buffers (*).
Often, for text streams, it does "line buffering" (buffers get emptied after dealing with a '\n'). This appears to be your case. Your output des not contain a newline.
To force the buffers to be emptied, use fflush() for output operations.
printf("not a line");
fflush(stdout); // force buffer emptying
printf("complete line\n"); // line-buffering poses no issue here
(*) input streams may also be buffered, but the management of buffering for input is quite different

Creating a TCP Server to host ELF files

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.

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);

How to find out if the eth0 mode is static or dhcp?

I want to use a C program to get if the ip of the network interface is set manually or via dhcp.
I've tried to use the following code and it has worked in Debian, but it hasn't worked in OpenWrt. I want to know how to write a C program doing this in OpenWrt.
I have tried to use this:
#include <stdio.h>
int main(void)
{
FILE *fp;
char buffer[80];
fp=popen("cat /etc/network/interfaces |grep ^iface\\ br-lan | awk -F ' ' '{print $4}'","r");
fgets(buffer, sizeof(buffer), fp);
printf("%s", buffer);
pclose(fp);
}
This code is working in Debian, but it isn't working normally in OpenWrt, so I want to know how to write a program to get the same result.
for OpenWRT you can get a such information with the following command:
$uci get network.lan.proto
so I take the program you put in your question and I change only the command used to get information:
#include <stdio.h> <br>
int main(void)
{
FILE *fp;
char buffer[80];
fp=popen("uci get network.lan.proto","r");
fgets(buffer, sizeof(buffer), fp);
printf("%s", buffer);
pclose(fp);
}
to see all network interfaces available in your OpenWRT you can use the following command:
$uci show network
You can avoid using calling linux command in your c by using the libuci. The libuci contains C function to execute uci commands without passing via popen ( popen is used to execute external command from shell).
The libuci exist by default in the development environment of OpenWRT, not need to download it, no need to build it and no need to install it on your OpenWRT machine
You can use libuci in this way
#include <uci.h>
void main()
{
char path[]="network.lan.proto";
char buffer[80];
struct uci_ptr ptr;
struct uci_context *c = uci_alloc_context();
if(!c) return;
if ((uci_lookup_ptr(c, &ptr, path, true) != UCI_OK) ||
(ptr.o==NULL || ptr.o->v.string==NULL)) {
uci_free_context(c);
return;
}
if(ptr.flags & UCI_LOOKUP_COMPLETE)
strcpy(buffer, ptr.o->v.string);
uci_free_context(c);
printf("%s\n", buffer);
}
(Not tested)
and when you compile your program you have to add the -luci in the compilation command gcc
There's no required way for an OS to decide how an interface should be configured. The kernel (the Linux part of e.g. GNU/Linux) doesn't decide, it doesn't (and shouldn't) care, it just gets told which network addresses go with which interfaces by whatever configuration system the OS is using. OpenWRT's not GNU, it operates differently.
There is AFAIK no definitive way.
Reading the interfaces file would be a hint only: there is no guarantee that the current seup came from there.
You could look at 'asking' the DBUS interface if there is one.
You could check for a dhclient process running.
You could check other files in /etc that specify network setup on different distros.
I think the most reliable option would be a multi-layered thing: check a whole host of hints to come up with the answer.
Another option: send a DHCP check packet to the dhcp server to verify the address.. if you don't get an answer though it could be that the network is down but was up when the address was allocated.

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.

Resources