Bitcoin Forum
June 24, 2024, 10:08:09 AM *
News: Voting for pizza day contest
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Bitcoin and Litecoin Research Part 2  (Read 499 times)
j0kie_smurf (OP)
Newbie
*
Offline Offline

Activity: 6
Merit: 0


View Profile
June 19, 2015, 07:51:51 PM
 #1

 This is the second part of my research into Bitcoins. This part will cover IRC connections, hidden channels and backdoors, if they exist. There are several Bitcoin wallets that use an IRC connection for node discovery. This is not an incorrect way to discover nodes or wallets connected to the network, but it does come with vulnerabilities. Some of these vulnerabilities are well known to malicious users and are easy to exploit.

 One of the typical IRC connections used is irc.lfnet.com. Litecoin, for example, uses this connection, but also points to: pelican.heliacal.net. The connection is not hidden, but does have a vulnerability present. A user's I.P. address is made public. If the current connection is not available, a different IRC channel can be used. While this helps keep connections alive, it could be made a little more secure. This block of litecoin code shows how it connects to IRC.

// Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    CNetAddr addr(strHost, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr;

    return true;
}



void ThreadIRCSeed(void* parg)
{
    IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));

    // Make this thread recognisable as the IRC seeding thread
    RenameThread("bitcoin-ircseed");

    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exited\n");
}

void ThreadIRCSeed2(void* parg)
{
    /* Dont advertise on IRC if we don't allow incoming connections */
    if (mapArgs.count("-connect") || fNoListen)
        return;

    if (!GetBoolArg("-irc", false))
        return;

    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;

    while (!fShutdown)
    {
        CService addrConnect("irc.lfnet.org", 6667, true);

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
         addrConnect = CService("pelican.heliacal.net", 6667, true);
         if (!ConnectSocket(addrConnect, hSocket))
         {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
               continue;
            else
               return;
         }
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
        CService addrLocal;
        string strMyName;
        if (GetLocal(addrLocal, &addrIPv4))
            strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
        if (strMyName == "")
            strMyName = strprintf("x%"PRI64u"", GetRand(1000000000));

        Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
        Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

        int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
        if (nRet != 1)
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            if (nRet == 2)
            {
                printf("IRC name already in use\n");
                Wait(10);
                continue;
            }
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }
        MilliSleep(500);

        // Get our external IP from the IRC server and re-nick before joining the channel
        CNetAddr addrFromIRC;
        if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
        {
            printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
            if (addrFromIRC.IsRoutable())
            {
                // IRC lets you to re-nick
                AddLocal(addrFromIRC, LOCAL_IRC);
                strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
                Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
            }
        }

 Another vulnerability here is the seeding aspect. Seeding implies that the connection is available for downloading from. Just like torrent files are seeded to share, so are connections like this. With the right scripts in place, it is possible to download the user's data, and potentially misuse it. Not all of the IRC connections used by crypto currencies are malicious. The vulnerabilities that exist within these connections are in need of being corrected. Any IRC servers being used to host these connections should only be administrated by trusted individuals that you know, and have a reputation of being honest. If you use a connection that you are unsure of, or is ran anonymously, you run the risk of being exploited. Once a connection is open as a seed, a firewall is little protection. Some antivirus programs will be effective against malware being passed through the connection. But any connection allowed through the firewall, is open to exploitation.

 I would recommend researching a particular IRC connection, before using any software that connects to it. Look for who owns the server, who is the administrator and if there has been any previous incidents involving the server. Blind acceptance of the security of a given server is foolish. Blind acceptance of the claim of anonymity and security of a given network is also foolish. Again, if you don't know who runs the server, you run the risk of getting exploited.

 There is a seed filter set up, but it is limited to only a specific set of addresses. Any address not listed bypasses the filter and thus could be used to exploit connections. By limiting the number of addresses to check for suspicion, it limits the protection of the filter. Instead of filtering by I.P. only, there could be additional checks in place to check for suspicious activity on any connection, not just those specified.

#!/usr/bin/env python
#
# Generate seeds.txt from Pieter's DNS seeder
#

NSEEDS=512

MAX_SEEDS_PER_ASN=2

MIN_BLOCKS = 337600

# These are hosts that have been observed to be behaving strangely (e.g.
# aggressively connecting to every node).
SUSPICIOUS_HOSTS = set([
    "130.211.129.106", "178.63.107.226",
    "83.81.130.26", "88.198.17.7", "148.251.238.178", "176.9.46.6",
    "54.173.72.127", "54.174.10.182", "54.183.64.54", "54.194.231.211",
    "54.66.214.167", "54.66.220.137", "54.67.33.14", "54.77.251.214",
    "54.94.195.96", "54.94.200.247"
])

import re
import sys
import dns.resolver

PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):9333$")
PATTERN_AGENT = re.compile(r"^(\/Satoshi:0.8.6\/|\/Satoshi:0.9.(2|3)\/|\/Satoshi:0.10.\d{1,2}\/)$")

def parseline(line):
    sline = line.split()
    if len(sline) < 11:
       return None
    # Match only IPv4
    m = PATTERN_IPV4.match(sline[0])
    if m is None:
        return None
    # Do IPv4 sanity check
    ip = 0
    for i in range(0,4):
        if int(m.group(i+2)) < 0 or int(m.group(i+2)) > 255:
            return None
        ip = ip + (int(m.group(i+2)) << (8*(3-i)))
    if ip == 0:
        return None
    # Skip bad results.
    if sline[1] == 0:
        return None
    # Extract uptime %.
    uptime30 = float(sline[7][:-1])
    # Extract Unix timestamp of last success.
    lastsuccess = int(sline[2])
    # Extract protocol version.
    version = int(sline[10])
    # Extract user agent.
    agent = sline[11][1:-1]
    # Extract service flags.
    service = int(sline[9], 16)
    # Extract blocks.
    blocks = int(sline[8])
    # Construct result.
    return {
        'ip': m.group(1),
        'ipnum': ip,
        'uptime': uptime30,
        'lastsuccess': lastsuccess,
        'version': version,
        'agent': agent,
        'service': service,
        'blocks': blocks,
    }

# Based on Greg Maxwell's seed_filter.py
def filterbyasn(ips, max_per_asn, max_total):
    result = []
    asn_count = {}
    for ip in ips:
        if len(result) == max_total:
            break
        try:
            asn = int([x.to_text() for x in dns.resolver.query('.'.join(reversed(ip['ip'].split('.'))) + '.origin.asn.cymru.com', 'TXT').response.answer][0].split('\"')[1].split(' ')[0])
            if asn not in asn_count:
                asn_count[asn] = 0
            if asn_count[asn] == max_per_asn:
                continue
            asn_count[asn] += 1
            result.append(ip)
        except:
            sys.stderr.write('ERR: Could not resolve ASN for "' + ip['ip'] + '"\n')
    return result

def main():
    lines = sys.stdin.readlines()
    ips = [parseline(line) for line in lines]

    # Skip entries with valid IPv4 address.
    ips = [ip for ip in ips if ip is not None]
    # Skip entries from suspicious hosts.
    ips = [ip for ip in ips if ip['ip'] not in SUSPICIOUS_HOSTS]
    # Enforce minimal number of blocks.
    ips = [ip for ip in ips if ip['blocks'] >= MIN_BLOCKS]
    # Require service bit 1.

 Using a filter does add to the protection of a connection. More IRC connections could be using filters to help reduce the number of malicious connections. Filtering out known suspicious connections helps, but additional filters need to be implemented. This particular filter checks IPv4 and should be changed to also include IPv6 connections.


 Netcoin uses a very similar IRC connection to litecoin. Many portions of code mirror litecoin or have striking similarities.

// Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    CNetAddr addr(strHost, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr;

    return true;
}



void ThreadIRCSeed(void* parg)
{
    IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));

    // Make this thread recognisable as the IRC seeding thread
    RenameThread("bitcoin-ircseed");

    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exited\n");
}

void ThreadIRCSeed2(void* parg)
{
    /* Dont advertise on IRC if we don't allow incoming connections */
    if (mapArgs.count("-connect") || fNoListen)
        return;

    if (!GetBoolArg("-irc", false))
        return;

    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;

    while (!fShutdown)
    {
        CService addrConnect("irc.lfnet.org", 6667, true);

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
         addrConnect = CService("pelican.heliacal.net", 6667, true);
         if (!ConnectSocket(addrConnect, hSocket))
         {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
               continue;
            else
               return;
         }
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

 The same lfnet server is used, which is not unusual. It also uses the same pelican.heliacal.net connection used by litecoin. There are a lot of similarities between these 2 coins. They have the same vulnerabilities present and also employ the same seeding architecture. I.P. addresses of users are made public and may be exploited in the same fashion as previously pointed out in litecoin. Multiple coins are being passed through the same server, on the same channel and being operated by the same person. There was talk that the IRC functions are merely leftover from previous projects. This is false. None of the IRC has been commented out or changed. It points to a server that is still active and is sniffing seed traffic. Further research will be required to identify if this is a malicious connection or not.
emelac
Full Member
***
Offline Offline

Activity: 184
Merit: 100



View Profile
June 19, 2015, 08:05:21 PM
 #2

Is there any simple way that non-techies can easily understand to disable IRC connections to a wallet and only connect through lists of nodes in a conf file?

Are all wallets vulnerable to IRC hacks or do only some of them use IRC?
achow101
Staff
Legendary
*
Offline Offline

Activity: 3430
Merit: 6720


Just writing some code


View Profile WWW
June 19, 2015, 08:11:30 PM
 #3

Bitcoin Core no longer supports IRC bootstrapping. The functionality was removed in version 0.8.2 and it was disabled by default in version 0.6. However this concern is still valid for altcoins that forked Bitcoin prior to this change. Obviously something was not good about IRC bootstrapping in Bitcoin Core, be it possibility of attacks or something else, so it was removed. I would assume that the IRC server the client connected to by default was trusted because it was run by the developer(s) of the coin, although they could be malicious also.

You also mention that IP addresses will be public. By virtue of running a full node, and by being on the internet in general, your IP address will be publicly known.

Good luck on your research, looks like good stuff. Also, can you put code that you find in code brackets? It will make these easier to follow and the post won't be as long.

Nxtblg
Legendary
*
Offline Offline

Activity: 924
Merit: 1000



View Profile WWW
June 20, 2015, 01:51:39 PM
 #4

Props to ya for being one of the few to actually look through the sourcecode. When you get to altcoins, you're in for a certain treat. Before you buckle down, try looking for all the places where "Bitcoin" and/or Bitcoin parameters are still in the comments. Smiley






██████████████████████████████████████████████████████████████████████████████████████████████
██████████████████████████████████████████████████████████████████████████████████████
███████████████████████████████████████████████████████████████████████▄▄▄███████████████████████
███████████████████████████████████████████████████████████████████████▀▀▀████████████████████████
██████████████████████████████████████████████████████████████████████████████████████████████████
█████████████████████████████████████████████████████████████████████████████████████████████████





...INTRODUCING WAVES........
...ULTIMATE ASSET/CUSTOM TOKEN BLOCKCHAIN PLATFORM...






Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!