programing

버퍼 오버플로는 gdb에서 동작하지만 없으면 동작하지 않는다.

goodcopy 2022. 8. 11. 23:58
반응형

버퍼 오버플로는 gdb에서 동작하지만 없으면 동작하지 않는다.

CentOS 6.4 32비트를 사용하고 있으며 프로그램에서 버퍼 오버플로를 일으키려고 합니다.GDB 내에서 동작합니다.출력은 다음과 같습니다.

[root@localhost bufferoverflow]# gdb stack
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/bufferoverflow/stack...done.
(gdb) r
Starting program: /root/bufferoverflow/stack
process 6003 is executing new program: /bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686
sh-4.1#

그러나 프로그램 스택을 단독으로 실행하면 오류가 분할됩니다.왜 그럴까?

디버깅 프로세스에 비결정론을 도입하는 요소를 적절히 고려하지 않으면 개발 악용은 심각한 골칫거리로 이어질 수 있습니다.특히 디버거의 스택주소가 통상적인 실행중의 주소와 일치하지 않는 경우가 있습니다.이 아티팩트는 운영 체제 로더가 환경 변수와 프로그램 인수를 모두 스택 시작 전에 배치하기 때문에 발생합니다.

Process layout

취약한 프로그램은 인수를 사용하지 않으므로 환경 변수가 원인일 수 있습니다.호출, 셸, 디버거 모두 동일한지 확인합니다.이를 위해 호출을 다음과 같이 랩할 수 있습니다.env:

env - /path/to/stack

디버거를 사용하면:

env - gdb /path/to/stack
($) show env
LINES=24
COLUMNS=80

위의 예에서는 gdb에 의해2개의 환경변수가 설정되어 있습니다.이러한 환경변수는 더욱 디세블로 할 수 있습니다.

unset env LINES
unset env COLUMNS

지금이다show env빈 목록을 반환해야 합니다.이 시점에서 디버깅프로세스를 시작하여 점프할 예정인 절대 스택주소를 찾을 수 있습니다(예:0xbffffa8b이를 부정 이용에 하드코드합니다.

한 가지 더 미묘하지만 중요한 세부 사항: 전화와 전화는 다른 점이 있습니다../stack그리고./path/to/stack: 이후argv[0]에는, 기동한 그대로의 프로그램이 보관 유지되기 때문에, 기동 문자열이 같게 되어 있는 것을 확인할 필요가 있습니다.그래서 제가/path/to/stack뿐만 아니라 위의 예에서도./stack그리고.gdb stack.

메모리의 안전성에 관한 취약성을 부정 이용하는 방법을 배울 때는 다음 래퍼 프로그램을 사용할 것을 권장합니다.이 프로그램은 무거운 리프팅을 하고 스택 오프셋을 균등하게 합니다.

$ invoke stack         # just call the executable
$ invoke -d stack      # run the executable in GDB

스크립트는 다음과 같습니다.

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
      exit 0
      ;;
    t)
      tty=1
      gdb=1
      ;;
    d)
      gdb=1
      ;;
    e)
      env=$OPTARG
      ;;
  esac
done

shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
shift
if [ -n "$gdb" ] ; then
  if [ -n "$tty" ]; then
    touch /tmp/gdb-debug-pty
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "$@"
  else
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "$@"
  fi
else
  exec env - $env TERM=screen PWD=$PWD $prog "$@"
fi

gdb에서 코드를 실행할 때 스택프레임 포인터의 주소는 정상적으로 실행할 때와 다릅니다.따라서 gdb 모드에서 바로 반환 주소가 파손될 수 있지만 일반 모드에서 실행 중일 때는 올바르게 반환되지 않을 수 있습니다.그 주된 이유는 두 상황 사이의 환경 변수가 다르기 때문이다.

데모일 뿐이므로 피해자 코드를 변경하여 버퍼의 주소를 출력할 수 있습니다.그런 다음 반환 주소를 offset+address of buffer로 변경합니다.

그러나 실제로는 악성코드 전에 NOP 스레드 추가를 반환 주소로 추측해야 합니다.그리고 여러분의 추측이 틀릴 수도 있기 때문에 정확한 주소를 얻기 위해 여러 번 추측할 수도 있습니다.

이게 도움이 되길 바라.

터미널과 터미널에서 동일한 스택을 사용하여 프로그램을 실행하는 간단한 방법은 다음과 같습니다.gdb:

먼저 프로그램이 스택 보호 없이 컴파일되었는지 확인합니다.

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

ASLR이 비활성화되어 있습니다.

echo 0 > /proc/sys/kernel/randomize_va_space

메모: 컴퓨터의 기본값은 2입니다.변경하기 전에 자신의 설정을 확인해 주세요.

그런 다음 다음과 같이 프로그램을 실행합니다(각각 터미널 및 gdb).

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest

이내에gdb, 반드시unset LINES그리고.COLUMNS.

주의: 이러한 환경변수는 테스트 프로그램을 가지고 노는 것으로 얻을 수 있습니다.

이 두 번의 실행으로 스택의 맨 위에 동일한 포인터가 제공되므로 원격으로 호스트된 바이너리를 이용하려고 할 경우 원격 스크립트가 필요하지 않습니다.

버퍼 오버플로우가 gdb 및 segfaults에서 동작하는 이유는 gdb가 주소 공간 레이아웃 랜덤화를 디세블로 하기 때문입니다.gdb 버전7에서는 디폴트로 켜져 있었던 것 같습니다.

이를 확인하려면 다음 명령을 수행합니다.

show disable-randomization

그리고 세팅은

set disable-randomization on

또는

set disable-randomization off

여기서 받아들여지는 해결책을 시도해 봤지만 효과가 없다.gdb가 환경변수를 추가했기 때문에 스택주소가 일치하지 않는다는 것을 알고 있었습니다만, 이 변수를 삭제해도 gdb가 없으면 악용할 수 없습니다(승인된 솔루션에 게재된 스크립트도 시험해 보았습니다).

그러나 웹 검색에서 나에게 맞는 다른 스크립트를 찾았습니다.https://github.com/hellman/fixenv/blob/master/r.sh

용도는 기본적으로 허용되는 솔루션의 스크립트와 동일합니다.

  • r.sh gdb ./program [s]를 클릭하여 gdb에서 프로그램을 실행합니다.
  • r.sh ./program [s]를 사용하여 gdb 없이 프로그램을 실행합니다.

그리고 이 대본은 나에게 효과가 있다.

CentOS 6.4 32비트를 사용하고 있으며 프로그램에서 버퍼 오버플로를 발생시키려고 합니다.그러나 프로그램 스택을 단독으로 실행하면 오류가 분할됩니다.

또한 FORTIFY_SOURCE가 결과에 영향을 미치지 않는지 확인해야 합니다.세그먼트 장애는 FORTIFY_SOURCE처럼 들립니다.이는 FORTIFY_SOURCE가 버퍼 오버플로우를 방지하기 위해 "안전" 함수 호출을 삽입하기 때문입니다.컴파일러가 수신처 버퍼 사이즈를 추론할 수 있는 경우는, 사이즈가 체크되고,abort()는 위반으로 호출됩니다(즉, 세그먼트 폴트).

테스트를 위해 FORTIFY_SOURCE를 끄려면 다음 명령을 사용하여 컴파일해야 합니다.-U_FORTIFY_SOURCE또는-D_FORTIFY_SOURCE=0.

gdb 외부에서 발생하지 않는 gdb의 주요 기능 중 하나는 제로 메모리입니다.코드 내 어딘가에서 메모리를 초기화하지 않고 가비지 값을 얻을 가능성이 높습니다.GDB는 이러한 유형의 오류를 숨기고 할당한 모든 메모리를 자동으로 지웁니다.

예를 들어, 다음 항목은 gdb에서는 동작하지만 gdb 밖에서는 동작하지 않습니다.

int main(){
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside
    if (temp[0] != NULL){
        *temp[0] = 1; //segfault outside of gdb
    }
    return 0;
}

이 문제를 검출할 수 있는지 확인하려면 , 밸린더로 프로그램을 실행해 주세요.

가장 좋은 방법은 gdb로 바이너리 프로세스를 첨부하여setarch -R <binary>이진수에 대해서만 ASLR 보호를 일시적으로 비활성화합니다.이 방법에서는 gdb 내부 및 외부 스택프레임은 같아야 합니다.

언급URL : https://stackoverflow.com/questions/17775186/buffer-overflow-works-in-gdb-but-not-without-it

반응형