Адрес памяти переменной среды печати Python

Возможно ли распечатать адрес памяти переменной окружения?

С gdb-peda у меня есть адрес памяти, похожий на 0xbffffcd6 с searchmem, и я знаю его в правильной форме. (0xbfff????), но gdb переместил стек с другой переменной среды.

Я хотел бы с моим python script получить этот адрес, а затем сделать свой трюк и включить мой шеллкод.

Я попробовал (с Python):

print hex(id(os.environ["ENVVAR"]))
print memoryview(os.environ["ENVVAR"])

# output :
# 0xb7b205c0L
# <memory at 0xb7b4dd9c>

С Ruby:

puts (ENV['PATH'].object_id << 1).to_s(16)
# output :
# -4836c38c

Если у кого-то есть идея, с python или ruby.

Ответ 1

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

Например, мы имеем переменную x. id (x) не возвращает адрес памяти переменной x, а возвращает адрес памяти объекта, на который указывает x.

Там существует строгое разделение между "переменными" и "объектами памяти". В стандартной реализации python выделяет набор локалей и стек для виртуальной машины. Все локальные слоты не пересекаются, поэтому, если вы загружаете объект из локального слота x в стек и изменяете этот объект, "местоположение" слота x не изменяется.

введите описание изображения здесь http://docs.python.org/library/functions.html#id

Ответ 2

Это кажется невыполнимой задачей, по крайней мере, в python. Из этого вопроса следует принять во внимание несколько факторов:

  • ASLR сделает это совершенно невозможным
  • Каждый двоичный файл может иметь собственные накладные расходы, разные argv, поэтому единственным надежным вариантом является выполнение двоичного файла и отслеживание его памяти до тех пор, пока мы не найдем переменную среды, которую мы ищем. В принципе, даже если мы сможем найти адрес окружения в процессе python, он будет находиться в другом месте в двоичном файле, который вы пытаетесь использовать.

Лучше всего ответить на этот вопрос - использовать http://python3-pwntools.readthedocs.io/en/latest/elf.html, который берет файл coredump, где легко найти адрес.

Ответ 3

Я полагаю, вы могли бы это сделать, используя ctypes модуль, чтобы напрямую вызвать нативный getenv:

import ctypes

libc = ctypes.CDLL("libc.so.6")

getenv = libc.getenv
getenv.restype = ctypes.c_voidp

print('%08x' % getenv('PATH'))

Ответ 4

Имейте в виду, что переменная системной среды не является объектом, к которому вы можете получить доступ по адресу своей памяти. Каждый процесс, такой как Python или Ruby, запускающий ваш script, получит свою собственную копию среды. Вот почему результаты, возвращаемые интерпретаторами Python и Ruby, настолько различны.

Если вы хотите изменить переменную системной среды, вы должны использовать API, предоставляемый вашим языком программирования. См. этот или который для решения Python.

Ответ 5

  Функция getenv() по своей сути не реентерабельна, потому что она возвращает значение, указывающее на статические данные.

Фактически, для более высокой производительности getenv() реализация также может поддерживать отдельную копию среды в структуре данных, которую можно искать гораздо быстрее (например, индексированную хеш-таблицу или двоичное дерево), и обновлять оба это и линейный список в среде, когда вызывается setenv() или unsetenv().

Таким образом, адрес, возвращаемый getenv, не обязательно должен быть из среды.

Расположение памяти процесса;


(источник: duartes.org)


(источник: cloudfront.net)

Карта памяти

import os

def mem_map():
    path_hex = hex(id(os.getenv('PATH'))).rstrip('L')
    path_address = int(path_hex, 16)
    for line in open('/proc/self/maps'):
        if 'stack' in line:
            line = line.split()
            first, second = line[0].split('-')
            first, second = int(first, 16), int(second, 16)
            #stack grows towards lower memory address
            start, end = max(first, second), min(first, second)
            print('stack:\n\tstart:\t0x{}\n\tend:\t0x{}\n\tsize:\t{}'.format(start, end, start - end))
            if path_address in range(end, start+1):
                print('\tgetenv("PATH") ({}) is in the stack'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not in the stack'.format(path_hex))
            if path_address > start:
                print('\tgetenv("PATH") ({}) is above the stack'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not above the stack'.format(path_hex))
            print('')
            continue
        if 'heap' in line:
            line = line.split()
            first, second = line[0].split('-')
            first, second  = int(first, 16), int(second, 16)
            #heap grows towards higher memory address
            start, end = min(first, second), max(first, second)
            print('heap:\n\tstart:\t0x{}\n\tend:\t0x{}\n\tsize:\t{}'.format(start, end, end - start))
            if path_address in range(start, end+1):
                print('\tgetenv("PATH") ({}) in the heap'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not in the heap'.format(path_hex))
            print('')

выход;

heap:
        start:  0x170364928
        end:    0x170930176
        size:   565248
        getenv("PATH") (0xb74d2330) is not in the heap

stack:
        start:  0x0xbffa8000L
        end:    0x0xbff86000L
        size:   139264
        getenv("PATH") (0xb74d2330) is not in the stack
        getenv("PATH") (0xb74d2330) is not above the stack

Среда выше стека. Поэтому его адрес должен быть выше стека. Но адрес, который показывает id, находится не в стеке, не в куче и не над стеком. Это действительно адрес? или мой расчет неверен!

Здесь код, чтобы проверить, где находится объект в памяти.

def where_in_mem(obj):
    maps = {}
    for line in open('/proc/self/maps'):
        line = line.split()
        start, end = line[0].split('-')

        key = line[-1] if line[-1] != '0' else 'anonymous'
        maps.setdefault(key, []).append((int(start, 16), int(end, 16)))

    for key, pair in maps.items():
        for start, end in pair:
            # stack starts at higher memory address and grows towards lower memory address
            if 'stack' in key:
                if start >= id(obj) >= end:
                    print('Object "{}" ({}) in the range {} - {}, mapped to {}'.format(obj, hex(id(obj)), hex(start), hex(end), key))
                    continue
            if start <= id(obj) <= end:
                print('Object "{}" ({}) in the range {} - {}, mapped to {}'.format(obj, hex(id(obj)), hex(start), hex(end), key))

where_in_mem(1)
where_in_mem(os.getenv('PATH'))

выход;

Object "1" (0xa17f8b0) in the range 0xa173000 - 0xa1fd000, mapped to [heap]
Object "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" (0xb74a1330L) in the range 0xb7414000L - 0xb74d6000L, mapped to anonymous

Что анонимно в приведенном выше выводе?

Также можно создать отображение анонимной памяти, которое не соответствует никаким файлам, вместо этого оно используется для данных программы. В Linux, если вы запрашиваете большой блок памяти через malloc(), библиотека C создаст такое анонимное отображение вместо использования кучи памяти. ‘Большой означает больше байтов MMAP_THRESHOLD, 128 кБ по умолчанию и настраивается с помощью mallopt().

Анатомия программы в памяти

Таким образом, os.environ['PATH'] находится в malloc ed области.

Ответ 6

Спасибо за @mickael9, я написал функцию для вычисления адреса переменной среды в программе:

def getEnvAddr(envName, ELFfile):
  import ctypes
  libc = ctypes.CDLL('libc.so.6')
  getenv = libc.getenv
  getenv.restype = ctypes.c_voidp

  ptr = getenv(envName)
  ptr += (len('/usr/bin/python') - len(ELFfile)) * 2
  return ptr

Например:

[email protected]:~$ ./getenvaddr.elf PATH /bin/ls
PATH will be at 0xbfffff22 in /bin/ls
[email protected]:~$ python getenvaddr.py PATH /bin/ls
PATH will be at 0xbfffff22 in /bin/ls
[email protected]:~$

Примечание. Эта функция работает только в системе Linux.

Ответ 7

В рубине это возможно - этот пост охватывает общий случай: Доступ к адресу памяти объектов в ruby ​​..? "Вы можете получить фактическое значение указателя объекта, взяв идентификатор объекта и выполнив побитовый сдвиг влево"

puts (ENV['RAILS_ENV'].object_id << 1).to_s(16)
> 7f84598a8d58