문제

내 친구는 x86에서 작동하는 작은 개념 증명 어셈블러를 제작했습니다. 나는 x86_64를 위해 포트를하기로 결정했지만 즉시 문제를 쳤다.

나는 C로 작은 프로그램을 작성한 다음 코드를 컴파일하고 objdumped했습니다. 그 후 나는 파이썬 스크립트에 삽입 했으므로 x86_64 코드가 정확합니다.

from ctypes import cast, CFUNCTYPE, c_char_p, c_long

buffer = ''.join(map(chr, [ #0000000000000000 <add>:
  0x55,                     # push   %rbp
  0x48, 0x89, 0xe5,         # mov    %rsp,%rbp
  0x48, 0x89, 0x7d, 0xf8,   # mov    %rdi,-0x8(%rbp)
  0x48, 0x8b, 0x45, 0xf8,   # mov    -0x8(%rbp),%rax
  0x48, 0x83, 0xc0, 0x0a,   # add    $0xa,%rax
  0xc9,                     # leaveq 
  0xc3,                     # retq
]))

fptr = cast(c_char_p(buffer), CFUNCTYPE(c_long, c_long))
print fptr(1234)

이제이 스크립트가 실행할 때마다 세그먼트 화 결함을 계속하는 이유는 무엇입니까?

나는 아직 mprotect에 대한 질문이 있고 실행 플래그가 없습니다. 버퍼 오버런과 같은 대부분의 기본 보안 익스플로잇으로부터 보호한다고합니다. 그러나 그것이 사용중인 진짜 이유는 무엇입니까? .text에 부딪 칠 때까지 계속 글을 쓰고 지시 사항을 멋진 Prot_Exec -Area에 주입 할 수 있습니다. 물론 .text에서 쓰기 보호를 사용하지 않는 한

그러나 어쨌든 왜 그 prot_exec이 어디에나있는 이유는 무엇입니까? .text 섹션이 쓰여진 것이 막히는 것이 엄청나게 도움이되지 않습니까?

도움이 되었습니까?

해결책

처럼 빈센트 언급하면, 이것은 할당 된 페이지가 비 실행 파일로 표시되어 있기 때문입니다. 최신 프로세서가이를 지원합니다 기능, OS의 추가 보안 계층으로 사용되는 OS의 추가 보안 계층으로 사용됩니다. 아이디어는 특정 버퍼 오버플로 공격으로부터 보호하는 것입니다. 예를 들어. 일반적인 공격은 스택 변수를 오버 플로우하여 리턴 주소를 삽입 한 코드를 가리키도록 다시 작성하는 것입니다. 실행 불가능한 스택을 사용하면 이제 프로세스 제어보다는 Segfault 만 생성합니다. 힙 메모리에 대해서도 비슷한 공격도 존재합니다.

주위를 돌리려면 보호를 변경해야합니다. 이것은 페이지 정렬 된 메모리에서만 수행 할 수 있으므로 코드를 다음과 같은 것과 같은 것으로 변경해야 할 것입니다.

libc = CDLL('libc.so')

# Some constants
PROT_READ = 1
PROT_WRITE = 2
PROT_EXEC = 4

def executable_code(buffer):
    """Return a pointer to a page-aligned executable buffer filled in with the data of the string provided.
    The pointer should be freed with libc.free() when finished"""

    buf = c_char_p(buffer)
    size = len(buffer)
    # Need to align to a page boundary, so use valloc
    addr = libc.valloc(size)
    addr = c_void_p(addr)

    if 0 == addr:  
        raise Exception("Failed to allocate memory")

    memmove(addr, buf, size)
    if 0 != libc.mprotect(addr, len(buffer), PROT_READ | PROT_WRITE | PROT_EXEC):
        raise Exception("Failed to set protection on buffer")
    return addr

code_ptr = executable_code(buffer)
fptr = cast(code_ptr, CFUNCTYPE(c_long, c_long))
print fptr(1234)
libc.free(code_ptr)

참고 : 페이지를 제거하기 전에 실행 파일을 설정하지 않는 것이 좋습니다. 대부분의 C 라이브러리는 완료되면 실제로 메모리를 OS로 반환하지 않지만 자체 수영장에 보관합니다. 이는 보안 혜택을 우회하지 않고 EXEC 비트를 지우지 않고 다른 곳에서 페이지를 재사용 할 수 있음을 의미 할 수 있습니다.

또한 이것은 상당히 포트가 불가능합니다. Linux에서 테스트했지만 다른 OS에서는 테스트하지 않았습니다. Windows에서는 작동하지 않으며 구매는 다른 유닉스 (BSD, OSX?)에서 할 수 있습니다.

다른 팁

내 친구와의 연구를 마쳤으며 이것이 플랫폼 별 문제라는 것을 알았습니다. 일부 플랫폼에서 Malloc은 Prot_Exec없이 메모리를 MMAPS하고 다른 플랫폼에서는 MMAPS 메모리를 의심합니다.

따라서 나중에 mprotect로 보호 수준을 변경해야합니다.

절름발이, 무엇을 해야하는지 알아내는 데 시간이 걸렸습니다.

from ctypes import (
    cast, CFUNCTYPE, c_long, sizeof, addressof, create_string_buffer, pythonapi
)

PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC = 0, 1, 2, 4
mprotect = pythonapi.mprotect

buffer = ''.join(map(chr, [ #0000000000000000 <add>:
    0x55,                     # push   %rbp
    0x48, 0x89, 0xe5,         # mov    %rsp,%rbp
    0x48, 0x89, 0x7d, 0xf8,   # mov    %rdi,-0x8(%rbp)
    0x48, 0x8b, 0x45, 0xf8,   # mov    -0x8(%rbp),%rax
    0x48, 0x83, 0xc0, 0x0a,   # add    $0xa,%rax
    0xc9,                     # leaveq 
    0xc3,                     # retq
]))

pagesize = pythonapi.getpagesize()
cbuffer = create_string_buffer(buffer)#c_char_p(buffer)
addr = addressof(cbuffer)
size = sizeof(cbuffer)
mask = pagesize - 1
if mprotect(~mask&addr, mask&addr + size, PROT_READ|PROT_WRITE|PROT_EXEC) < 0:
    print "mprotect failed?"
else:
    fptr = cast(cbuffer, CFUNCTYPE(c_long, c_long))
    print repr(fptr(1234))

먼저 실행 파일로 설정하지 않고 할당 된 메모리를 자유롭게 실행할 수 없다고 생각합니다. 나는 나 자신을 시도한 적이 없지만 유닉스 기능을 확인하고 싶을 수도 있습니다. mprotect:

http://linux.about.com/library/cmd/blcmdl2_mprotect.htm

VirtualProtect Windows에서 똑같은 일을하는 것 같습니다.

http://msdn.microsoft.com/en-us/library/aa366898(vs.85).aspx

Python은 그러한 사용을 허용합니까? 나는 그것을 배워야한다 ...

통역사가 레지스터가 변경 될 것으로 기대하지 않는다고 생각합니다. 어셈블러 출력을 사용하려는 경우 기능 내에서 사용하는 레지스터를 저장하십시오.

BTW, X86_64의 통화 규칙은 일반 X86과 다릅니다. 스택 포인터 정렬을 잃고 다른 도구와 생성 된 외부 객체를 혼합하면 문제가있을 수 있습니다.

내가 생각했던 더 간단한 접근법이 있지만 최근에는 mprotect와 관련이 없습니다. 프로그램 용 실행 가능한 공간을 직접 MMAP에 직접 MMAP하십시오. 요즘 Python에는 정확히이 작업을 수행하기위한 모듈이 있지만 코드의 주소를 얻는 방법을 찾지 못했습니다. 요컨대 문자열 버퍼를 사용하고 실행 플래그를 간접적으로 설정하는 대신 메모리 호출 MMAP를 할당합니다. 이것은 더 쉽고 안전합니다. 이제 코드 만 실행할 수 있는지 확인할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top