Angr-CTF学习笔记11-14

11_angr_sim_scanf

汇编代码:

.text:0804862A                 push    14h             ; n
.text:0804862C                 push    0               ; c
.text:0804862E                 lea     eax, [ebp+key_string]
.text:08048631                 push    eax             ; s
.text:08048632                 call    _memset
.text:08048637                 add     esp, 10h
.text:0804863A                 lea     eax, [ebp+key_string]
.text:0804863D                 mov     dword ptr [eax], 444E4848h
.text:08048643                 mov     dword ptr [eax+4], 50484156h  ;  初始化Key-String
.text:0804864A                 mov     [ebp+index], 0
.text:08048651                 jmp     short loc_8048680
.text:08048653 ; ---------------------------------------------------------------------------
.text:08048653
.text:08048653 loc_8048653:                            ; CODE XREF: main+8F↓j
.text:08048653                 lea     edx, [ebp+key_string]
.text:08048656                 mov     eax, [ebp+index]
.text:08048659                 add     eax, edx
.text:0804865B                 movzx   eax, byte ptr [eax]
.text:0804865E                 movsx   eax, al
.text:08048661                 sub     esp, 8
.text:08048664                 push    [ebp+index]
.text:08048667                 push    eax
.text:08048668                 call    complex_function  ;  complex_function() 对key-string 进行计算
.text:0804866D                 add     esp, 10h
.text:08048670                 mov     ecx, eax
.text:08048672                 lea     edx, [ebp+key_string]
.text:08048675                 mov     eax, [ebp+index]
.text:08048678                 add     eax, edx
.text:0804867A                 mov     [eax], cl
.text:0804867C                 add     [ebp+index], 1
.text:08048680
.text:08048680 loc_8048680:                            ; CODE XREF: main+5C↑j
.text:08048680                 cmp     [ebp+index], 7
.text:08048684                 jle     short loc_8048653 ; for (index =0 index <=7 ; ++ index )

程序第一步先对Key-String 进行运算,该题的难点在于main() 里面多个scanf() .

text:08048689                 push    offset aEnterThePasswo ; "Enter the password: "
.text:0804868E                 call    _printf
.text:08048693                 add     esp, 10h
.text:08048696                 cmp     [ebp+var_24], 0DEADBEEFh
.text:0804869D                 jnz     loc_804C196
.text:080486A3                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486AA                 jnz     loc_804A423
.text:080486B0                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486B7                 jz      loc_8049570
.text:080486BD                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486C4                 jnz     loc_8048E1D
.text:080486CA                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486D1                 jz      loc_8048A7A
.text:080486D7                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486DE                 jz      loc_80488AF
.text:080486E4                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486EB                 jnz     loc_80487D0
.text:080486F1                 cmp     [ebp+var_24], 0DEADBEEFh
.text:080486F8                 jnz     short loc_8048765
.text:080486FA                 sub     esp, 4
.text:080486FD                 push    offset buffer1
.text:08048702                 push    offset buffer0
.text:08048707                 push    offset aUU      ; "%u %u"
.text:0804870C                 call    ___isoc99_scanf
.text:08048711                 add     esp, 10h
.text:08048714                 cmp     [ebp+var_2C], 0
.text:08048718                 jz      short loc_8048758
.text:0804871A                 sub     esp, 4
.text:0804871D                 push    4               ; n
.text:0804871F                 lea     eax, [ebp+key_string]
.text:08048722                 push    eax             ; s2
.text:08048723                 push    offset buffer0  ; s1
.text:08048728                 call    _strncmp
.text:0804872D                 add     esp, 10h
.text:08048730                 test    eax, eax
.text:08048732                 jnz     short loc_8048758
.text:08048734                 sub     esp, 4
.text:08048737                 push    4               ; n
.text:08048739                 lea     eax, [ebp+key_string]
.text:0804873C                 add     eax, 4
.text:0804873F                 push    eax             ; s2
.text:08048740                 push    offset buffer1  ; s1
.text:08048745                 call    _strncmp
.text:0804874A                 add     esp, 10h
.text:0804874D                 test    eax, eax
.text:0804874F                 jnz     short loc_8048758
.text:08048751                 mov     eax, 1
.text:08048756                 jmp     short loc_804875D
.text:08048758 ; ---------------------------------------------------------------------------
.text:08048758
.text:08048758 loc_8048758:                            ; CODE XREF: main+123↑j
.text:08048758                                         ; main+13D↑j ...
.text:08048758                 mov     eax, 0
.text:0804875D
.text:0804875D loc_804875D:                            ; CODE XREF: main+161↑j
.text:0804875D                 mov     [ebp+var_2C], eax
.text:08048760                 jmp     loc_804FC81
.text:08048765 ; ---------------------------------------------------------------------------
.text:08048765
.text:08048765 loc_8048765:                            ; CODE XREF: main+103↑j
.text:08048765                 sub     esp, 4
.text:08048768                 push    offset buffer1
.text:0804876D                 push    offset buffer0
.text:08048772                 push    offset aUU      ; "%u %u"
.text:08048777                 call    ___isoc99_scanf
.text:0804877C                 add     esp, 10h
.text:0804877F                 cmp     [ebp+var_2C], 0
.text:08048783                 jz      short loc_80487C3
.text:08048785                 sub     esp, 4
.text:08048788                 push    4               ; n
.text:0804878A                 lea     eax, [ebp+key_string]
.text:0804878D                 push    eax             ; s2
.text:0804878E                 push    offset buffer0  ; s1
.text:08048793                 call    _strncmp
.text:08048798                 add     esp, 10h
.text:0804879B                 test    eax, eax
.text:0804879D                 jnz     short loc_80487C3
.text:0804879F                 sub     esp, 4
.text:080487A2                 push    4               ; n
.text:080487A4                 lea     eax, [ebp+key_string]
.text:080487A7                 add     eax, 4
.text:080487AA                 push    eax             ; s2
.text:080487AB                 push    offset buffer1  ; s1
.text:080487B0                 call    _strncmp
.text:080487B5                 add     esp, 10h
.text:080487B8                 test    eax, eax
.text:080487BA                 jnz     short loc_80487C3
.text:080487BC                 mov     eax, 1
.text:080487C1                 jmp     short loc_80487C8

我们的关注点在于scanf() ,这里标明了用户有两个输入,分别为4 字节.然后我们就需要Hook scanf() 来对buffer 进行符号构造,代码如下:

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)

  initial_state = project.factory.entry_state()

  class ReplacementScanf(angr.SimProcedure):

    def run(self, format_string, scanf0_address, scanf1_address ):
      scanf0 = claripy.BVS('scanf0', 4 * 8)
      scanf1 = claripy.BVS('scanf1', 4 * 8)

      self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
      self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)

      self.state.globals['solution0'] = scanf0
      self.state.globals['solution1'] = scanf1

  scanf_symbol = '__isoc99_scanf'
  project.hook_symbol(scanf_symbol, ReplacementScanf())

  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Good Job' in str(stdout_output)

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Try again' in str(stdout_output)

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]
    stored_solutions0 = solution_state.globals['solution0']
    stored_solutions1 = solution_state.globals['solution1']
    solution0 = solution_state.se.eval(stored_solutions0)
    solution1 = solution_state.se.eval(stored_solutions1)

    print(solution0,solution1)

12_angr_veritesting

汇编代码:

.text:080485ED                 push    21h             ; n
.text:080485EF                 push    0               ; c
.text:080485F1                 lea     eax, [ebp+input_buffer]
.text:080485F4                 push    eax             ; s
.text:080485F5                 call    _memset
.text:080485FA                 add     esp, 10h
.text:080485FD                 sub     esp, 0Ch
.text:08048600                 push    offset aEnterThePasswo ; "Enter the password: "
.text:08048605                 call    _printf
.text:0804860A                 add     esp, 10h
.text:0804860D                 sub     esp, 8
.text:08048610                 lea     eax, [ebp+input_buffer]
.text:08048613                 push    eax
.text:08048614                 push    offset a32s     ; "%32s"
.text:08048619                 call    ___isoc99_scanf  ;  用户输入一个32字节的Buffer
.text:0804861E                 add     esp, 10h
.text:08048621                 mov     [ebp+var_3C], 0
.text:08048628                 mov     [ebp+var_34], 0
.text:0804862F                 mov     [ebp+index], 0
.text:08048636                 jmp     short loc_8048666
.text:08048638 ; ---------------------------------------------------------------------------
.text:08048638
.text:08048638 loc_8048638:                            ; CODE XREF: main+A5↓j
.text:08048638                 lea     edx, [ebp+input_buffer]
.text:0804863B                 mov     eax, [ebp+index]
.text:0804863E                 add     eax, edx
.text:08048640                 movzx   eax, byte ptr [eax]
.text:08048643                 movsx   ebx, al
.text:08048646                 mov     eax, [ebp+index]
.text:08048649                 add     eax, 5Bh
.text:0804864C                 sub     esp, 8
.text:0804864F                 push    eax
.text:08048650                 push    4Fh
.text:08048652                 call    complex_function  ;  对用户输入进行计算
.text:08048657                 add     esp, 10h
.text:0804865A                 cmp     ebx, eax
.text:0804865C                 jnz     short loc_8048662
.text:0804865E                 add     [ebp+var_3C], 1
.text:08048662
.text:08048662 loc_8048662:                            ; CODE XREF: main+97↑j
.text:08048662                 add     [ebp+index], 1
.text:08048666
.text:08048666 loc_8048666:                            ; CODE XREF: main+71↑j
.text:08048666                 cmp     [ebp+index], 1Fh
.text:0804866A                 jle     short loc_8048638
.text:0804866C                 cmp     [ebp+var_3C], ' '
.text:08048670                 jnz     short loc_804868C
.text:08048672                 movzx   eax, byte ptr [ebp+var_C]
.text:08048676                 test    al, al
.text:08048678                 jnz     short loc_804868C  ;  对输入进行计算
.text:0804867A                 sub     esp, 0Ch
.text:0804867D                 push    offset aGoodJob ; "Good Job."
.text:08048682                 call    _puts
.text:08048687                 add     esp, 10h
.text:0804868A                 jmp     short loc_804869C
.text:0804868C ; ---------------------------------------------------------------------------
.text:0804868C
.text:0804868C loc_804868C:                            ; CODE XREF: main+AB↑j
.text:0804868C                                         ; main+B3↑j
.text:0804868C                 sub     esp, 0Ch
.text:0804868F                 push    offset s        ; "Try again."
.text:08048694                 call    _puts
.text:08048699                 add     esp, 10h

这个示例和01 题是一样的,唯独不同的一点是这个循环比之前的要大,导致直接用01 题的解题方法不能直接计算出结果,因为循环过大导致路径爆炸,所以在执行的时候会消耗很多资源.

幸运的是,project.factory.simgr() 函数提供veritesting 参数来指定是否要自动合并路径,避免路径爆炸的问题.具体细节参考论文:https://users.ece.cmu.edu/~dbrumley/pdf/Avgerinos%20et%20al._2014_Enhancing%20Symbolic%20Execution%20with%20Veritesting.pdf

import angr
import sys


project = angr.Project(sys.argv[1])
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state,veritesting = True)

def is_successful(state):
  stdout_output = state.posix.dumps(sys.stdout.fileno())
  return 'Good Job.' in str(stdout_output)  # :boolean

def should_abort(state):
  stdout_output = state.posix.dumps(sys.stdout.fileno())
  return 'Try again.' in str(stdout_output)  # :boolean

simulation.explore(find = is_successful,avoid = should_abort)

if simulation.found :
  solution_state = simulation.found[0]
  print(solution_state.posix.dumps(sys.stdin.fileno()))

Angr函数使用总结:

project.factory.simgr(初始化状态,veritesting = True) => veritesting 默认为False

##13_angr_static_binary

汇编代码:

.text:08048953                 push    offset aEnterThePasswo ; "Enter the password: "
.text:08048958                 call    printf
.text:0804895D                 add     esp, 10h
.text:08048960                 sub     esp, 8
.text:08048963                 lea     eax, [ebp+s1]
.text:08048966                 push    eax
.text:08048967                 push    offset a8s      ; "%8s"
.text:0804896C                 call    __isoc99_scanf  ;  用户输入
.text:08048971                 add     esp, 10h
.text:08048974                 mov     [ebp+var_38], 0
.text:0804897B                 jmp     short loc_80489AA
.text:0804897D ; ---------------------------------------------------------------------------
.text:0804897D
.text:0804897D loc_804897D:                            ; CODE XREF: main+B0↓j
.text:0804897D                 lea     edx, [ebp+s1]
.text:08048980                 mov     eax, [ebp+var_38]
.text:08048983                 add     eax, edx
.text:08048985                 movzx   eax, byte ptr [eax]
.text:08048988                 movsx   eax, al
.text:0804898B                 sub     esp, 8
.text:0804898E                 push    [ebp+var_38]
.text:08048991                 push    eax
.text:08048992                 call    complex_function
.text:08048997                 add     esp, 10h
.text:0804899A                 mov     ecx, eax
.text:0804899C                 lea     edx, [ebp+s1]
.text:0804899F                 mov     eax, [ebp+var_38]
.text:080489A2                 add     eax, edx
.text:080489A4                 mov     [eax], cl
.text:080489A6                 add     [ebp+var_38], 1
.text:080489AA
.text:080489AA loc_80489AA:                            ; CODE XREF: main+7D↑j
.text:080489AA                 cmp     [ebp+var_38], 7
.text:080489AE                 jle     short loc_804897D  ;  使用for 循环不断调用complex_function() 对数据进行计算
.text:080489B0                 sub     esp, 8
.text:080489B3                 lea     eax, [ebp+s2]
.text:080489B6                 push    eax             ; s2
.text:080489B7                 lea     eax, [ebp+s1]
.text:080489BA                 push    eax             ; s1
.text:080489BB                 call    _strcmp
.text:080489C0                 add     esp, 10h
.text:080489C3                 test    eax, eax
.text:080489C5                 jz      short loc_80489D9
.text:080489C7                 sub     esp, 0Ch
.text:080489CA                 push    offset aTryAgain ; "Try again."
.text:080489CF                 call    puts
.text:080489D4                 add     esp, 10h
.text:080489D7                 jmp     short loc_80489E9
.text:080489D9 ; ---------------------------------------------------------------------------
.text:080489D9
.text:080489D9 loc_80489D9:                            ; CODE XREF: main+C7↑j
.text:080489D9                 sub     esp, 0Ch
.text:080489DC                 push    offset aGoodJob ; "Good Job."
.text:080489E1                 call    puts
.text:080489E6                 add     esp, 10h
.text:080489E9

这个示例的逻辑和01 题是一样的,主要不同的地方是在于这个程序是静态链接编译的,所以程序中包含了一些libc 的函数实现,但是这里可能会存在两个问题:1.这些函数里面隐藏一些出题人的坑;2.这些函数里面的实现可能会依赖其他的系统函数或者实现方式不相同.所以12 题主要是让我们通过Hook 的方式重定向函数中被调用的libc 的函数

首先,Linux 下启动main() 函数需要通过__libc_start_main 对程序进行初始化,然后再跳转到main() 函数;其次,在main() 函数里面调用了printf ,scanf ,puts ,所以我们需要通过Hook 来重定向它们.

幸运的是,我们不需要重新实现这些函数的实现,Angr 代码库里面已经帮我们实现了一部分libc 的函数库,所以我们只需要倒入它们即可.

import angr
import sys


project = angr.Project(sys.argv[1])
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state,veritesting = True)

project.hook(0x804ed40, angr.SIM_PROCEDURES['libc']['printf']())
project.hook(0x804ed80, angr.SIM_PROCEDURES['libc']['scanf']())
project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())

def is_successful(state):
  stdout_output = state.posix.dumps(sys.stdout.fileno())
  return 'Good Job.' in str(stdout_output)  # :boolean

def should_abort(state):
  stdout_output = state.posix.dumps(sys.stdout.fileno())
  return 'Try again.' in str(stdout_output)  # :boolean

simulation.explore(find = is_successful,avoid = should_abort)

if simulation.found :
  solution_state = simulation.found[0]
  print(solution_state.posix.dumps(sys.stdin.fileno()))

Angr函数使用总结:

angr.SIM_PROCEDURES[ 系统库名 ] [ 系统函数名 ] () => 获取Angr 内部实现的系统函数

14_angr_shared_library

编译14_angr_shared_library 存在一个小坑,就是在执行命令Python generate.py 1234 14_angr_shared_library 时会报错,内容如下:

root@sec:~/angr_ctf/14_angr_shared_library# python generate.py 1234 14_angr_shared_library
gcc: error: 14_angr_shared_library: No such file or directory

这是因为generate.py 里面有一个Bug ,在最后的一个gcc 编译命令因为-L 参数缺少了指定当前目录,导致在寻找lib14_angr_shared_library.so 的时候找到了系统库目录,所以gcc 抛出了这个找不到14_angr_shared_library: No such file or directory 的问题,代码修改如下:

  with tempfile.NamedTemporaryFile(delete=False, suffix='.c') as temp:
    temp.write(c_code)
    temp.seek(0)
-    os.system('gcc -m32 -I . -L ' + '/'.join(output_file.split('/')[0:-1]) + ' -o ' + output_file + ' ' + temp.name + ' -l' + output_file.split('/')[-1])
+    os.system('gcc -m32 -I . -L . ' + '/'.join(output_file.split('/')[0:-1]) + ' -o ' + output_file + ' ' + temp.name + ' -l' + output_file.split('/')[-1])

程序汇编代码如下:

.text:080486A2                 push    10h             ; n
.text:080486A4                 push    0               ; c
.text:080486A6                 lea     eax, [ebp+s]
.text:080486A9                 push    eax             ; s
.text:080486AA                 call    _memset
.text:080486AF                 add     esp, 10h
.text:080486B2                 sub     esp, 0Ch
.text:080486B5                 push    offset format   ; "Enter the password: "
.text:080486BA                 call    _printf
.text:080486BF                 add     esp, 10h
.text:080486C2                 sub     esp, 8
.text:080486C5                 lea     eax, [ebp+s]
.text:080486C8                 push    eax
.text:080486C9                 push    offset a8s      ; "%8s"
.text:080486CE                 call    ___isoc99_scanf ;  用户输入
.text:080486D3                 add     esp, 10h
.text:080486D6                 sub     esp, 8
.text:080486D9                 push    8
.text:080486DB                 lea     eax, [ebp+s]
.text:080486DE                 push    eax
.text:080486DF                 call    _validate       ;  调用验证
.text:080486E4                 add     esp, 10h
.text:080486E7                 test    eax, eax
.text:080486E9                 jz      short loc_80486FD
.text:080486EB                 sub     esp, 0Ch
.text:080486EE                 push    offset s        ; "Good Job."
.text:080486F3                 call    _puts

_validate() 函数是在另一个so 库中存在的,我们继续分析完当前程序的代码

.plt:08048550 _validate       proc near               ; CODE XREF: main+64↓p
.plt:08048550                 jmp     ds:off_804A020
.plt:08048550 _validate       endp

.got.plt:0804A020 off_804A020     dd offset validate 

extern:0804A04C                 extrn validate:near 

我们来分析一下lib14_angr_shared_library.so 的代码:

.text:000006D7                 public validate
.text:000006D7 validate        proc near               ; DATA XREF: LOAD:00000250↑o
.text:000006D7
.text:000006D7 s2              = byte ptr -24h
.text:000006D7 var_10          = dword ptr -10h
.text:000006D7 var_C           = dword ptr -0Ch
.text:000006D7 s1              = dword ptr  8
.text:000006D7 arg_4           = dword ptr  0Ch
.text:000006D7
.text:000006D7 ; __unwind {
.text:000006D7                 push    ebp
.text:000006D8                 mov     ebp, esp
.text:000006DA                 push    esi
.text:000006DB                 push    ebx
.text:000006DC                 sub     esp, 20h
.text:000006DF                 call    __x86_get_pc_thunk_bx
.text:000006E4                 add     ebx, 191Ch
.text:000006EA                 cmp     [ebp+arg_4], 7
.text:000006EE                 jg      short loc_6FA
.text:000006F0                 mov     eax, 0
.text:000006F5                 jmp     loc_77D
.text:000006FA ; ---------------------------------------------------------------------------
.text:000006FA

;  .....

14 题主要是把程序逻辑分离在一个执行程序和动态链接库,我们直接对动态链接库中的_validate 函数进行符号执行,解决的solver.py 如下:

def main(argv):
  path_to_binary = sys.argv[1]  #  注意我们是要load so 库而不是执行程序

  base = 0x400000  #  base 基址是随意定的,可以随意修改
  project = angr.Project(path_to_binary, load_options={
    'main_opts' : {
      'custom_base_addr' : base
    }
  })

  buffer_pointer = claripy.BVV(0x3000000, 32)  #  创建一个buffer 指针值
  validate_function_address = base + 0x6D7
  initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8, 32))  #  调用validate_function,因为函数声明validata_function(buffer_point,buffer_length) ,所以我们构造出调用validata_function(0x3000000,0x8) .

  password = claripy.BVS('password', 8 * 8)  #  创建一个求解对象,大小为8 字节
  initial_state.memory.store(buffer_pointer, password)  #  保存到0x30000000

  simulation = project.factory.simgr(initial_state)

  simulation.explore(find = base + 0x783)  #  执行到validate 函数的RETN 指令

  if simulation.found:
    solution_state = simulation.found[0]

    solution_state.add_constraints(solution_state.regs.eax != 0)  #  记得,我们要求validate 函数的返回值为1 的时候就是有解的,那么我们就需要在求解的时候添加上这么一个求解约束条件EAX 不能为False .
    solution = solution_state.se.eval(password)
    print(solution)

点击关注,共同学习!
安全狗的自我修养

github haidragon

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值