Angr CTF 用法笔记

在github找到了一个关于Angr CTF相关的题目,进行一个初探Angr 自动化的学习,方便以后进行自动化漏洞挖掘papa

1.00_angr_find:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [esp+1Ch] [ebp-1Ch]
  char s1[9]; // [esp+23h] [ebp-15h] BYREF
  unsigned int v6; // [esp+2Ch] [ebp-Ch]

  v6 = __readgsdword(0x14u);
  printf("Enter the password: ");
  __isoc99_scanf("%8s", s1);
  for ( i = 0; i <= 7; ++i )
    s1[i] = complex_function(s1[i], i);
  if ( !strcmp(s1, "JACEJGCS") )
    puts("Good Job.");
  else
    puts("Try again.");
  return 0;
}

complex_function:

int __cdecl complex_function(int a1, int a2)
{
  if ( a1 <= 64 || a1 > 90 )
  {
    puts("Try again.");
    exit(1);
  }
  return (3 * a2 + a1 - 65) % 26 + 65;
}

此题逻辑很简单,相当于一个比较的re题,现在来初探下如何用angr工具进行解题
这里简单来说下angr吧,angr我认为就是一个寻求最优的路径的一个工具,也是传说的自动化
ange使用流程:

  • 创建项目project
  • 设置state
  • 新建符号量:BVS或BVV
  • 把符号量设置到内存
  • 设置Simulation Managers,进行路径探索对象
  • 运行,求出满足逻辑需要的值
  • 求解,获取执行结果
    angr.Project(path_to_binary, auto_load_libs=False)

此函数是创建项目,auto_load_libs是用来标识是否装载库
i_state = project.factory.entry_state()
此函数告诉引擎是函数的入口开始
s = project.factory.simgr(initial_state)
进行一个启动,也就是实例
simulation.explore(find=0x8048678)
此函数是用来进行寻求最优路径的一个目标,这里主要设置成正确函数的位置,方便下面进行破解
if s.found:

    solution_state = s.found[0]  # 获取通过 explore 找到符合条件的状态
    solution = solution_state.posix.dumps(sys.stdin.fileno())
    print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))

获取最优的条件,并且打印出来的
exp:

import angr
import sys
project = angr.Project("./00_angr_find", auto_load_libs=False)
i_state = project.factory.entry_state()
s = project.factory.simgr(i_state)

s.explore(find=0x8048678)
if s.found:
    solution_state = s.found[0]
    solution = solution_state.posix.dumps(sys.stdin.fileno())
    print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
else:
    raise Exception('Could not find the solution')

01_angr_avoid:
此题代码量极大,无法f5,我们用一个工具进行dump出来源代码
https://github.com/avast/retdec,这个项目在这里不在具题论述

这里在if判断中出现两种函数,一种是正确的函数,一种是不正确的,所以这里引用一个避免入函的一个变量就是avoid,这个设置其不进入的函数地址

直接exp:

import angr
import sys

project = angr.Project("./00_angr_find", auto_load_libs=False)
i_state = project.factory.entry_state()
s = project.factory.simgr(i_state)

s.explore(find=0x80485E0,avoid=0x80485A8)
if s.found:
    solution_state = s.found[0]
    solution = solution_state.posix.dumps(sys.stdin.fileno())
    print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
else:
    raise Exception('Could not find the solution')

02_angr_find_condition:
此题和上一题一样,就是每次记录正确的地址较为麻烦,这里自己来定义函数字符串进行查找
exp:

import angr
import sys
def Go():
    path_to_binary = "./02_angr_find_condition" 
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Good Job.' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Try again.' in  stdout_output:
            return True
        else: 
            return False

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

    if simulation.found:
        solution_state = simulation.found[0]
        solution = solution_state.posix.dumps(sys.stdin.fileno())
        print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go()

03_angr_simbolic_registers
看下此题逻辑:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 user_input; // rax
  int v5; // [esp+4h] [ebp-14h]
  int v6; // [esp+8h] [ebp-10h]
  int v7; // [esp+Ch] [ebp-Ch]
  int v8; // [esp+Ch] [ebp-Ch]

  printf("Enter the password: ");
  user_input = get_user_input();
  v7 = HIDWORD(user_input);
  v5 = complex_function_1(user_input);
  v6 = complex_function_2();
  v8 = complex_function_3(v7);
  if ( v5 || v6 || v8 )
    puts("Try again.");
  else
    puts("Good Job.");
  return 0;
}

此题用了三个函数,三个值,在get_user_input
接收了三个值,也就代表了scanf的限制在三个值而不是一个值,这就导致了我们scanf的时候直接导致了无法输入,我们可以控制寄存器
exp:

import angr
import sys
import claripy
def Go():
    path_to_binary = "./03_angr_symbolic_registers" 
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address = 0x08048980
    initial_state = project.factory.blank_state(addr=start_address)

    passwd_size_in_bits = 32
    passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
    passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)
    passwd2 = claripy.BVS('passwd2', passwd_size_in_bits)

    initial_state.regs.eax = passwd0
    initial_state.regs.ebx = passwd1
    initial_state.regs.edx = passwd2

    simulation = project.factory.simgr(initial_state) 

    def is_successful(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

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

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = format(solution_state.solver.eval(passwd0), 'x')
            solution1 = format(solution_state.solver.eval(passwd1), 'x')
            solution2 = format(solution_state.solver.eval(passwd2), 'x')
            solution = solution0 + " " + solution1 + " " + solution2
            print("[+] Success! Solution is: {}".format(solution))
            # print(simgr.found[0].posix.dumps(0))
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go()

start_address = 0x08048980
initial_state = project.factory.blank_state(addr=start_address)
新建一个状态
passwd_size_in_bits = 32
passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)
passwd2 = claripy.BVS('passwd2', passwd_size_in_bits)
创建三个位向量,并且为每个向量赋予32位大小的size,为下面存放到寄存器做准备
initial_state.regs.eax = passwd0
initial_state.regs.ebx = passwd1
initial_state.regs.edx = passwd2
将三个向量放到寄存器里
solution0 = format(solution_state.solver.eval(passwd0), 'x')
solution1 = format(solution_state.solver.eval(passwd1), 'x')
solution2 = format(solution_state.solver.eval(passwd2), 'x')
solution = solution0 + " " + solution1 + " " + solution2
print("[+] Success! Solution is: {}".format(solution))
约束求解,并且打印出来

未完持续

本文链接:

http://azly.top/index.php/archives/42/
1 + 5 =
快来做第一个评论的人吧~