텍스트파일에서 가장 빈도수가 많은 단어 출력

name = input('Enter file:')
handle = open(name)

di = dict()
for line in handle:
    words = line.split()
    for word in words:
        di[word] = di.get(word,0) + 1

largest = -1
theword = None
for name, count in di.items() :
    if count > largest : 
        largest = count
        theword = name
        
print('Done', theword, largest)

 

딕셔너리 정렬

- 먼저, 튜플의 특성: 불변 속성, 여러 값끼리 한 번에 비교 가능, 딕셔너리 .item() 메소드는 (키,값) 쌍인 튜플의 리스트를 반환

(0, 1, 2) < (5, 1, 2)
# True
(0, 1, 2000000) < (0, 3, 4)
# True
( 'Jones', 'Sally' ) < ('Jones', 'Sam')
# True
( 'Jones', 'Sally') > ('Adams', 'Sam')
# True

- 키를 기준으로 정렬

d = {'b':1, 'a':10, 'c':22}
d.items()
# dict_items([('b', 1), ('a', 10), ('c', 22)])
sorted(d.items())
# [('a', 10), ('b', 1), ('c', 22)]

# OR

for k, v in sorted(d.items()):
    print(k, v)
# a 10
# b 1
# c 22

- 값을 기준으로 정렬

c = {'a':10, 'b':1, 'c':22}
tmp = list()
for k, v in c.items() :
    tmp.append( (v, k) )

print(tmp)	# [(10, 'a'), (1, 'b'), (22, 'c')]
tmp = sorted(tmp)
print(tmp)	# [(1, 'b'), (10, 'a'), (22, 'c')]


# 내림차순을 원할 경우
# tmp = sorted(tmp, reverse=True)

- 리스트 컴프리헨션 (List Comprehension)

c = {'a':10, 'b':1, 'c':22}
print( sorted( [ (v,k) for k,v in c.items() ] ) )
# [(1, 'b'), (10, 'a'), (22, 'c')]

 

가장 많이 등장한 단어 Top 10 출력

fhand = open('test.txt')
counts = {}	# "단어:빈도수" 인 딕셔너리
for line in fhand:
    words = line.split()
    for word in words:
        counts[word] = counts.get(word, 0 ) + 1

for val, key in sorted([ (v, k) in counts.items() ], reverse=True):
    print(key, val)

 

 

 

1. bash 쉘의 특징

  • Alias 기능 (명령어 단축 기능) ==> alias <별명>='원래 명령어'
  • History 기능 (이전 명령어 보기) ==> history 명령어 또는 위/아래 화살표 
  • 연산 기능
  • Job Control 기능
  • 자동 이름 완성 기능 ==> Tab 키
  • 프롬프트 제어 기능
  • 명령 편집 기능
  • 환경 변수
    • 환경변수 확인 ==> echo $환경변수이름
    • 환경변수 설정 ==> export 환경변수이름=값
    • echo $PATH : 명령어가 실행되는 경로 (해당 경로 내의 명령어가 기본 명령어)

 

2. 쉘 스크립트 실행 방법

  • 쉘 스크립트 프로그래밍은 별도로 컴파일하지 않고 텍스트 파일 형태로 바로 실행된다.
  • 리눅스의 많은 부분이 쉘 스크립트로 작성되어 있다. (C언어와 유사)
  • 쉘 스크립트 파일의 확장명 : .sh
  • 쉘 스크립트 파일을 /usr/local/bin/ 디렉토리에 복사하고, 속성을 755로 변경해주면 모든 사용자가 스크립트를 사용할 수 있다. (이 작업은 보안상 root만 수행함)
  • 쉘 스크립트 실행하는 두 가지 방법
    • sh <스크립트 파일>
    • chmod +x <스크립트 파일> && ./<스크립트파일>

      ex) name.sh
      -------------------------------------------------------------------------
      #! /bin/sh --> bin 아래 쉘을 사용한다는 의미로 반드시 써주어야 한다.
      echo "사용자이름: " $USERNAME
      echo "호스트이름: " $HOSTNAME
      exit 0
      -------------------------------------------------------------------------
      ~$ sh name.sh
      ~$ chmod +x name.sh
      ~$ ./name.sh
    • 현재 디렉토리임을 명시해야 한다. 환경변수에 디렉토리경로가 없으므로 name.sh 만 입력할 경우 명령어 탐색 실패라고 뜬다.

 

3. 쉘 스크립트 - 변수

  • 변수를 사용하기 전에 미리 선언하지 않으며, 변수에 처음 값이 할당되면서 자동으로 변수가 생성된다.
  • 모든 변수는 문자열(String)로 취급
  • 변수 이름은 대소문자를 구분
  • 변수를 대입할 때 '=' 좌우에는 공백이 없어야 한다.
  • 터미널에서 바로 입력 가능
  • 생성된 변수를 사용할 때는 항상 $를 앞에 붙인다.
    ~$ valName=Hello
    ~$ echo $valName
    ~$ valName="Yes Sir"        # 공백이 있으면 큰따옴표로 묶어줘야함
    ~$ echo $valName
  • 변수의 입력과 출력 : $ 문자가 들어간 글자를 출력하려면 ' ' 또는 " "로 내용물을 묶어서 대입하거나 앞에 역슬래쉬(\)를 붙인다.

    ex) var1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    myvar="Hi Woo"
    echo $myvar
    echo "\$myvar"         # 출력내용은 $myvar 이다.
    echo '\$myvar'
    echo \$myvar
    echo "값 입력: "
    read myvar        # 터미널에서 입력한 내용을 변수에 저장
    echo \$myvar = $myvar         # 문자열과 변수의 내용을 합한 것.
    exit 0
    --------------------------------------------------------------------------
    ~$ sh var1.sh

  • 변수에 들어 있는 값을 숫자로 해서 사칙 연산등을 하려면 expr 을 사용
  • 수식에 괄호 또는 곱하기(*)는 그 앞에 반드시 역슬래쉬(\)를 붙여야 한다.

    ex) var2.sh
    -------------------------------------------------------------------------
    #! /bin/sh
    num1=100
    num2=$num1+200
    echo $num2         # 문자열("100+200")로 출력된다.
    num3='expr $num1 + 200'
    echo $num3
    num4='expr \($num1 + 200 \)/10 \* 2'
    echo $num4
    exit 0
    -------------------------------------------------------------------------
    ~$ sh var2.sh

  • 파라미터 변수는 $0, $1, $2 ... 의 형태를 가진다.
    • 전체 파라미터는 $*로 표현
    • yum  -y  install  gftp
        $0   $1     $2     $3

      ex) paravar.sh
      -------------------------------------------------------------------------
      #! /bin/sh
      echo "실행파일 이름은 <$0>이다."
      echo "첫번째 파라미터는 <$1>이고, 두번째 파라미터는 <$2>다."
      echo "전체 파라미터는 <$*>다."
      exit 0
      -------------------------------------------------------------------------
      ~$ sh paravar.sh  값1  값2  값3
                       $0        $1   $2    $3

 

4. 쉘 스크립트 - 조건문

  • 기본 if문
      if [ 조건 ]
      then
        참일 경우 실행
      fi

    ex) if1.sh
    -------------------------------------------------------------------------
    #! /bin/sh
    if [ "woo" = "woo" ]
    then
      echo "참입니다."
    fi

    if [ "woo" != "woo" ]
    then
      echo "참입니다."
    else
      echo "거짓입니다."
    fi
    exit 0
    -------------------------------------------------------------------------
    ~$ sh if1.sh

  • 조건문에 들어가는 비교 연산자
    • -n "문자열" : 문자열이 NULL이 아니면 참
    • -z "문자열" : 문자열이 NULL이면 참
    • 수식1 -eq 수식2 : 두 수식이 같으면 참
    • 수식1 -ne 수식2 : 두 수식이 같지 않으면 참
    • 수식1 -gt 수식2 : 수식1이 더 크다면 참
    • 수식1 -ge 수식2 : 수식1이 크거나 같으면 참
    • 수식1 -lt 수식2 : 수식1이 작으면 참
    • 수식1 -le 수식2 : 수식1이 작거나 같으면 참
    • !수식 : 수식이 거짓이면 참
  • 파일과 관련된 조건
    • -d 파일이름 : 디렉토리이면 참
    • -e 파일이름 : 파일 존재하면 참
    • -f 파일이름 : 일반파일이면 참
    • -g 파일이름 : 파일에 set-group-id가 설정되면 참
    • -r 파일이름 : 파일이 읽기 가능이면 참
    • -s 파일이름 : 크기가 0이 아니면 참
    • -u 파일이름 : 파일에 set-user-id가 설정되면 참
    • -w 파일이름 : 파일이 쓰기 가능 상태이면 참
    • -x 파일이름 : 파일이 실행 가능 상태이면 참

      ex) if2.sh
      -------------------------------------------------------------------------
      #! /bin/sh
      fname=/lib/systemd/system/httpd.service
      if [ -f $fname ]
      then
        head -5 $fname
      else
        echo "웹 서버가 설치되지 않았습니다."
      fi
      exit 0
      -------------------------------------------------------------------------
      ~$ sh if2.sh
      또는
      ~$ chmod +x if2.sh
      ~$ ./if2.sh
  • case~esac 문 : 여러 가지 경우의 수가 있다면 case문 (다중분기), if문은 2중분기

    ex) case1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    case "$1" in
      start)
        echo "시작~~";;
      stop)
        echo "중지~~";;
      restart)
        echo "다시 시작~~";;
      *)
        echo "뭔지 모름~~";;
    esac
    exit 0
    --------------------------------------------------------------------------
    ~$ sh case1.sh stop

    ex) case2.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    echo "리눅스가 재미있나요? (yes/no)"
    read answer         # 사용자 입력값 받아오기
    case $answer in
      yes | y | Y | Yes | YES)
        echo "다행입니다."
        echo "더욱 열심히 하세요 ^^";;
      [nN]*)
        echo "안타깝네요. ㅠㅠ";;
      *)
        echo "yes 아니면 no만 입력했어야죠"
        exit 1;;
    esac
    exit 0
    --------------------------------------------------------------------------
    ~$ sh case2.sh

  • 관계 연산자
    • and는 -a 또는 && 를 사용
    • or는 -o 또는 || 를 사용

      ex) and_or.sh
      --------------------------------------------------------------------------
      #! /bin/sh
      echo "보고 싶은 파일명을 입력하세요."
      read fname
      if [ -f $fname ] && [ -s $fname ] ; then
        head -5 $fname
      else
        echo "파일이 없거나 크기가 0입니다."
      fi
      exit 0
      --------------------------------------------------------------------------
      ~$ sh and_or.sh

 

5. 쉘 스크립트 - 반복문

  • for 문
    for 변수 in 값1 값2 값3 ...
    do
      반복할 문장
    done

    ex) for1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    hap=0
    for i in 1 2 3 4 5 6 7 8 9 10       # 또는 for i in 'seq 1 10'
    do
      hap='exp $hap + $i'
    done
    echo "1부터 10까지의 합: "$hap
    exit 0
    --------------------------------------------------------------------------
    ~$ sh for1.sh

    ex) for2.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    for fname in $(ls *.sh)      # 해당 명령어의 결과로 나온 파일명을 변수에 대입
    do
      echo "--------$fname---------"
      head -3 $fname
    done
    exit 0
    --------------------------------------------------------------------------
    ~$ sh for2.sh
  • while 문
    ex) while1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    while [ 1 ]      # 또는 while [ : ]
    do
      echo "CentOS 7"
    done
    exit 0
    --------------------------------------------------------------------------

    ex) while2.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    hap=0
    i=1
    while [ $i -le 10 ]         # 또는 until [ $i -gt 10 ]  : 거짓인동안 계속 반복함.
    do
      hap='expr $hap + $i'
      i='expr $i + 1'
    done
    echo "1부터 10까지의 합:"$hap
    exit 0
    --------------------------------------------------------------------------
    ~$ sh while2.sh

    ex) while3.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    echo "비밀번호를 입력하세요."
    read mypass
    while [ $mypass != "1234" ]
    do
      echo "틀렸음. 다시 입력하세요."
      read mypass
    done
    echo "통과~~"
    exit 0
    --------------------------------------------------------------------------
    ~$ sh while3.sh

 

6. 쉘 스크립트 - 종료문

ex) break_continue_exit.sh
--------------------------------------------------------------------------
#! /bin/sh
echo "무한 반복 입력을 시작합니다.(b: break, c: continue, e: exit)"
while [ 1 ]; do
read input
case $input in
  b | B)
break ;;
  c | C)
echo "continue"를 누르면 while의 조건으로 돌아감"
continue ;;
  e | E)
echo "exit를 누르면 프로그램을 완전히 종료함"
exit 1 ;;
esac;
done
echo "break를 누르면 while을 빠져나와 지금 이 문장이 출력됨."
exit 0
--------------------------------------------------------------------------
~$ sh break_continue_exit.sh

 

7. 쉘 스크립트 - 사용자 정의 함수

  • 함수 기본구조
    FuncName () {
      # body
    }
    FuncName

    ex) func1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    myFunction () {
      echo "함수 안으로 들어왔음"
      return         # 함수 내에서만 사용되는 종료문으로 함수가 호출된 시점으로 돌아감
    }
    echo "프로그램을 시작합니다."
    myFunction
    echo "프로그램을 종료합니다."
    exit 0
    --------------------------------------------------------------------------
    ~$ sh func1.sh

  • 함수의 파라미터 사용
    FuncName () {
      # $1, $2, ... 등을 사용
    }
    FuncName $param1 $param2

    ex) func2.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    hap () {
      echo 'expr $1 + $2'
    }
    echo "10 더하기 20을 실행합니다."
    hap 10 20
    exit 0
    --------------------------------------------------------------------------
    ~$ sh func2.sh

 

8. 쉘 스크립트 - 내장 함수

  • eval : 문자열 자체를 명령문으로 인식하고 실행하기

    ex) eval.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    str="ls -l anaconda-ks.cfg"
    echo $str
    eval $str
    exit 0
    --------------------------------------------------------------------------
    ~$ sh eval.sh

  • export : 외부 변수로 선언해 준다. 즉, 선언한 변수를 다른 프로그램에서도 사용할 수 있도록
    해준다.

    ex) exp1.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    echo $var1
    echo $var2
    exit 0
    --------------------------------------------------------------------------

    ex) exp2.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    var1="지역 변수"
    export var2="외부 변수"
    sh exp1.sh        # exp1.sh 를 실행하는데 외부변수로 var2를 exp1.sh 에서 인식
    exit 0
    --------------------------------------------------------------------------
    ~$ sh exp2.sh

  • printf : 형식을 지정해서 출력

    ex) printf.sh
    --------------------------------------------------------------------------
    #! /bin/sh
    var1=100.5
    var2="재미있는 리눅스~~"
    printf "%5.2f \n\n \t %s \n" $var1 "$var2"
    exit
    --------------------------------------------------------------------------
    ~$ sh printf.sh

  • set $(명령어)
    • 리눅스 명령어를 결과로 사용하기 위해서는 $(명령어) 형식을 사용
    • 결과를 파라미터로 사용하고자 할 때는 set과 함께 사용

      ex) set.sh
      --------------------------------------------------------------------------
      #! /bin/sh
      echo "오늘 날짜는 $(date) 입니다."        # date 명령어 실행
      set $(date)
      echo "오늘은 $4 요일 입니다."        # 결과를 파라미터로 받음
      exit 0
      --------------------------------------------------------------------------
      ~$ sh set.sh
  • shift
    • 파라미터 변수를 왼쪽으로 한 단계씩 아래로 쉬프트 시킴
    • 10개가 넘는 파라미터 변수에 접근할 때 사용한다
    • 단, $0 파라미터 변수는 변경되지 않음
    • $10 은 $1뒤에 0이붙은 결과를 내보냄

      ex) shift1.sh
      --------------------------------------------------------------------------
      #! /bin/sh
      myfunc() {
        str=""
        while [ "$1" != "" ]; do
      str="$str $1"         # 이전의 파라미터들 값과 바뀌는 $1값이 합쳐짐.
      shift                      # $1이 계속해서 $2가 되고, $3이 되고, ... $10이 된다.
        done
        echo $str
      }
      myfunc AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK
      exit 0
      --------------------------------------------------------------------------

 

 

 

 

1. 개념

BROP: 소스코드 및 바이너리가 주어지지 않은 상태에서 프로세스의 상태 또는 출력내용으로 공격을 수행하는 기법

= ROP Chain + Brute Force

무작위 대입 과정이 있어서 시간이 오래걸림..

이 기법을 이해하기 앞서 다음 두 가지 가젯에 대해 이해해야 함

STOP Gadget : main() 함수 또는 취약한 함수를 다시 실행하는 주소 (_start 주소일 수도 있고 정말 함수의 시작주소 일 수도 있으나 결과적으로 복귀주소를 이 가젯으로 변경하면 프로세스는 처음 실행했을 때의 출력값을 보인다.)

BROP Gadget : 보통 libc_csu_init 함수에 있는 pop 6개 + ret 가젯을 의미하는데, 이처럼 레지스터를 많이 쓸 수 있는 희소한 가젯을 일컫는다. 이 가젯을 찾는 이유는 주변에 0x9 그리고 0x7 오프셋으로 pop rdi ; ret 가젯과 pop rsi ; ret 가젯을 찾을 수 있기 때문이다. 두 가젯은 모두 system() 함수에서 첫번째 인자로 /bin/sh 를 넣기 위해 사용된다.

[ 도식화 ]

 

2. 공격 순서

정말 아~~무것도 주어지지 않았기 때문에 메모리 릭부터 가젯 구성에 필요한 주소까지 전부 알아내야 한다.

단계를 나름 나눠봤는데 9단계나 된다;; (무엇?)

 

(1) 스택 오버플로우 크기 확인

복귀주소를 변경하기 때문에 당연히 스택에서 오버플로가 날 것을 예상할 수 있다. 간혹 CTF 에서 이 크기를 알려준다고 한다.

파이썬 스크립트로 brute forcing 해서 프로세스가 죽거나 기존의 출력결과와 다른 출력값을 낸다면 스택 오버플로를 의심할 수 있다.

 

(2) STOP Gadget 찾기

오버플로우 크기를 알고 있기 때문에 "A" * SIZE + CodeAddress 를 페이로드로 공격했을 때, 처음 출력값이 나오면 CodeAddress 가 STOP Gadget 이 된다.

** Code 영역을 알아야 하니 checksec 같은 툴을 써서 No PIE 인지 확인하면 될 것

** 코드 세그먼트 크기가 0x1000 이므로, 보통 오프셋은 0 ~ 0x1000 이다. 

당연히 Code Base Address 부터 오프셋 1씩 늘려주면서 찾아야 한다. 역시 brute forcing 이므로 시간이 걸림

 

(3) BROP Gadget 찾기

pop 6개 + ret 가젯을 찾는 과정이기 때문에 페이로드는 "A" * SIZE + CodeAddress + PARAM * 6 + STOP_GADGET 이 된다. PARAM * 6 은 더미로 채우는데 32비트면 4바이트 * 6 = 24 바이트 일 것이고 64비트면 8바이트 * 6 = 48바이트 가 된다.

공격했을 때 처음 출력내용이 그대로 나오면 CodeAddress 는 BROP Gadget 이 된다.

(pop 6개 + ret 이 성공했으니 처음 출력내용이 나오는거니까)

** pwntools 에 p32() 랑 p64() 쓰면 편하게 계산가능하다.

이 가젯을 찾는 이유는 근처에 pop rdi ; ret (offset: 0x9) 과 pop rsi ; ret (0x7) 가젯이 있어서라 했다.

따라서 여기서 얻은 CodeAddress + 0x9 또는 CodeAddress + 0x7 주소를 실제로 사용한다.

당연히 Code Base Address 부터 오프셋 1씩 늘려주면서 찾아야 한다. 역시 brute forcing 이므로 시간이 걸림

 

(4) Printable Function 주소 찾기

출력함수는 C 언어에서 printf 와 puts 함수가 있는데 둘의 차이는 출력했을 때 개행 문자 "\n"가 출력되는지이다.

printf 일 경우 위에서 설명한 가젯 2개를 모두 사용 --> pop rdi ; ret (BROP Gadget +0x9) 과 pop rsi ; ret (+0x7)

puts 일 경우 하나만 사용 --> pop rdi ; ret (BROP Gadget +0x9)

보통 puts 함수를 쓸거라 생각하고 brute forcing 을 한다.

페이로드는 "A" * SIZE + POP_RDI_GADGET + CodeBase + CodeAddress 이다.

CodeBase 는 코드 영역의 시작주소이고, CodeAddress는 Base 부터 오프셋 범위(0 ~ 0x1000) 내로 1씩 증가시킨다. 위 페이로드로 공격했을 때 출력결과가 "\x7fELF" 문자열을 포함한다면 CodeAddress 는 puts@plt 가 된다.

** 리눅스 실행파일은 ELF 구조라 무조건 코드영역의 첫 4바이트는 "\x7fELF"이다. 그래서 CodeBase를 인자로 주고 puts 인지 아닌지 알아낸다.

당연히 Code Base Address 부터 오프셋 1씩 늘려주면서 찾아야 한다. 역시 brute forcing 이므로 시간이 걸림

 

(5) 메모리 덤프

자 이제 puts@plt 를 알아냈으니 출력함수를 사용할 수 있다. 인자로 메모리 영역만 넣어주면 바이너리 정보를 제대로 얻어낼 수 있는 거다.

코드 영역만 필요하니 CodeBase ~ CodeBase + 0x1000 범위를 출력해서 덤프 파일을 만든다.

페이로드는 "A" * SIZE + POP_RDI_GADGET + CodeAddress + PUTS_PLT 가 된다.

** 계속 출력하다보면 프로세스가 처음 출력하는 문자열이 있는데 그 부분 전까지만 포함해야 한다.

보통 파이썬 코드로 data = response[:response.index(처음출력결과)] 라고 작성한다. 문자열의 index 함수는 발견못하면 -1 이라 끝까지 넣기 때문이다. 아무튼 저런식으로 data 를 계속 쌓아서 한번에 파일 출력을 해준다.

** 덤프 파일을 생성하면 리버싱 툴써서 분석한다. radare 를 많이 쓴다.

당연히 CodeAddress 는 오프셋 1씩 늘려주면서 찾아야 한다. 역시 brute forcing 이므로 시간이 걸림

 

(6) Printable Function 의 GOT 주소 찾기

radare 로 덤프한 메모리를 다음과 같은 명령어로 분석을 진행한다.

$ r2 -B <CodeBase> <DumpFileName>

>> pd 10 @ <puts@plt>

검색하면 plt 영역의 코드가 나오는데, 세그먼트 내에 오프셋으로 jmp 할 주소를 계산하기 때문에 실제 GOT 주소를 찾을 수 있다.

 

(7) 메모리 릭 (leak libc address)

puts@got.plt 주소를 인자로 puts@plt 를 호출한다. 이는 libc 영역의 주소를 릭해서 오프셋 계산을 하기 위함이다.

페이로드는 "A" * SIZE + POP_RDI_GADGET + PUTS_GOT + PUTS_PLT 이다.

출력값은 당연히 puts 의 시작주소일 것이다. 이 주소의 끝 3자리 숫자를 가지고 libc 를 탐색한다.

ASLR 걸려있으면 여기서부터는 아래 단계들이 원자적으로 수행되어야 한다.

 

(8) libc 탐색 후 오프셋 찾기

필요한 도구는 libc-databaseLibcSearcher 이다. 사용하기전에 어떤 라이브러리인지 파악해야 한다.

둘다 설치해서 사용법대로 system() 함수와 /bin/sh 문자열의 오프셋을 알아낼 수 있다.

릭한 주소 그대로 써도 되긴 하는데, puts 와 system 그리고 /bin/sh 의 오프셋을 알아낸 다음 익스를 짜는게 덜 귀찮다. (적어도 나는 그랬다.)

보통 LibcSearcher 모듈을 쓸 때 다음과 같이 쓴다.

from LibcSearcher import *

addr_puts_libc = 0x6f690	# 라이브러리에 따라 오프셋이 바뀔 수 있음.

lib = LibcSearcher('puts', addr_puts_libc)
libcBase = addr_puts_libc - lib.dump('puts')
system_addr = libcBase + lib.dump('system')
binsh_addr = libcBase + lib.dump('str_bin_sh')

print 'libc base : ' + hex(libcBase)
print 'system : ' + hex(system_addr)
print 'binsh : ' + hex(binsh_addr)

 

(9) 최종 익스플로잇

여기는 그냥 ROP 기법대로 하면 된다. 위 과정에서 알아낸 오프셋을 기반으로 libc base 에 더해서 실제 주소를 계산해서 페이로드를 짜면 된다.

페이로드는 "A" * SIZE + POP_RDI_GADGET + STR_BINSH_ADDR + SYSTEM_ADDR 이다.

 

 

Reference

https://www.lazenca.net/pages/viewpage.action?pageId=16810286

 

08.BROP(Blind Return Oriented Programming) - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List BROP(Blind Return Oriented Programming) 소프트웨어를 해킹할 때 대략 3가지의 형태의 공격대상이 있습니다.Open-source (예 :  Apache)Open-binary (예 : Internet Explorer)Closed-binary and source (예 :일부 독점 네트워크 서비스)BROP는 Closed-bin

www.lazenca.net

https://blog.h3x0r.kr/2018-12-30-brop/

 

BROP (Blind ROP)

BROP라는 주제로 글을 쓰게된 ipwn(안건희)입니다. 아직 완벽하게 연구했다고는 생각하지 않지만 지금까지의 연구과정을 예제를 통해서 포스팅하려 합니다. 목차 들어가면서 … 필요한 것 ? stop_gadget ? brop_gadget ? exploit 절차 Example binary Server setting Check overflow Get stop_gadget Get brop_gadget Get printable function Dump memory

blog.h3x0r.kr

 

위 자료는 Write-Up 이 있어서 참고하면 된다. 사용한 문제는 HCTF 2018 과 CodeGate 2018 예선문제이다.

(다른 문제 찾으면 추가예정)

 

 

'Security > System' 카테고리의 다른 글

CTF Summary  (0) 2020.02.07
[Heap Overflow] House Of Orange  (0) 2019.07.06
linux system call table  (0) 2019.07.03
[Linux] Lazy Binding  (0) 2019.06.30
ROP Gadget Dictionary  (0) 2019.06.30

+ Recent posts