Angr CTF 从入门到入门(1)

12 篇文章 0 订阅

angr是一个很厉害的二进制分析工具,能够实现很多自动化的逆向工作。最近正在学习,在看文档的时候发现了有个angrCTF的实战可以练习angr。

angrCTF:http://angr.oregonctf.org/
angr文档:https://docs.angr.io/

这篇文章会是这个系列的第一篇文章。写这个系列也是因为我本身是逆向新手,记忆力还不行,估计过几天就忘记这个工具怎么用了。故在此记录。第一篇就只记录angrCTF的前三道题,感觉这三道题比较类似。

另外,还发现了一个大佬写的关于这方面的教程,贴在这里(因为我写的太垃圾了):

https://github.com/ZERO-A-ONE/AngrCTF_FITM

00_angr_find

题目告诉我们00_angr_find这个二进制文件是一个输入正确密码,然后打印Good Job.否则输出Try Again.的小程序。我们的目标就是去找到这个密码。只要将下面的python代码处的???填好即可。

# Before you begin, here are a few notes about these capture-the-flag
# challenges.
#
# Each binary, when run, will ask for a password, which can be entered via stdin
# (typing it into the console.) Many of the levels will accept many different
# passwords. Your goal is to find a single password that works for each binary.
#
# If you enter an incorrect password, the program will print "Try again." If you
# enter a correct password, the program will print "Good Job."
#
# Each challenge will be accompanied by a file like this one, named
# "scaffoldXX.py". It will offer guidance as well as the skeleton of a possible
# solution. You will have to edit each file. In some cases, you will have to
# edit it significantly. While use of these files is recommended, you can write
# a solution without them, if you find that they are too restrictive.
#
# Places in the scaffoldXX.py that require a simple substitution will be marked
# with three question marks (???). Places that require more code will be marked
# with an ellipsis (...). Comments will document any new concepts, but will be
# omitted for concepts that have already been covered (you will need to use
# previous scaffoldXX.py files as a reference to solve the challenges.) If a
# comment documents a part of the code that needs to be changed, it will be
# marked with an exclamation point at the end, on a separate line (!).

import angr
import sys

def main(argv):
  # Create an Angr project.
  # If you want to be able to point to the binary from the command line, you can
  # use argv[1] as the parameter. Then, you can run the script from the command
  # line as follows:
  # python ./scaffold00.py [binary]
  # (!)
  path_to_binary = argv[1]  # :string
  project = angr.Project(path_to_binary)

  # Tell Angr where to start executing (should it start from the main()
  # function or somewhere else?) For now, use the entry_state function
  # to instruct Angr to start from the main() function.
  initial_state = project.factory.entry_state()

  # Create a simulation manager initialized with the starting state. It provides
  # a number of useful tools to search and execute the binary.
  simulation = project.factory.simgr(initial_state)

  # Explore the binary to attempt to find the address that prints "Good Job."
  # You will have to find the address you want to find and insert it here. 
  # This function will keep executing until it either finds a solution or it 
  # has explored every possible path through the executable.
  # (!)
  print_good_address = ???  # :integer (probably in hexadecimal)
  simulation.explore(find=print_good_address)

  # Check that we have found a solution. The simulation.explore() method will
  # set simulation.found to a list of the states that it could find that reach
  # the instruction we asked it to search for. Remember, in Python, if a list
  # is empty, it will be evaluated as false, otherwise true.
  if simulation.found:
    # The explore method stops after it finds a single state that arrives at the
    # target address.
    solution_state = simulation.found[0]

    # Print the string that Angr wrote to stdin to follow solution_state. This 
    # is our solution.
    print (solution_state.posix.dumps(sys.stdin.fileno()))
  else:
    # If Angr could not find a path that reaches print_good_address, throw an
    # error. Perhaps you mistyped the print_good_address?
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

下面这个angr程序就是去找到一个地址能够打印Good Job.。然后angr就会一直执行,直到找到一个满足条件的输入或者遍历完所有可执行路径。

然后问题来了,如何才能找到打印Good Job.的地址呢?一开始卡了半天,后面我试着用ida打开00_angr_find文件,生成了二进制程序的控制流图。
在这里插入图片描述
然后试着将有Good Job.这个基本块的地址放到问号里,结果输出一个字符串,再将这个字符串在angrCTF网站输进去,显示成功。真的是非常的amazing!
在这里插入图片描述

01_angr_avoid

万事开头难,搞定了第一个后,第二个就很简单了。python代码如下。主要是由于二进制非常大,我们需要设置一些angr避免执行的地址,加快符号执行的速度。

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  # Explore the binary, but this time, instead of only looking for a state that
  # reaches the print_good_address, also find a state that does not reach 
  # will_not_succeed_address. The binary is pretty large, to save you some time,
  # everything you will need to look at is near the beginning of the address 
  # space.
  # (!)
  print_good_address =  ???
  will_not_succeed_address = ???
  simulation.explore(find=print_good_address, avoid=will_not_succeed_address)

  if simulation.found:
    solution_state = simulation.found[0]
    print (solution_state.posix.dumps(sys.stdin.fileno()))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

代码中的第一个问号是表示打印good job的地址,第二个问号填的是打印try again的地址。还是和刚才一样,用ida打开二进制文件,会发现这次二进制文件比较大,不好生成可视化的控制流图。不过不影响。我们可以直接手撕汇编代码。
在这里插入图片描述
点击ida左侧的窗口,定位到main函数,在main函数上方有这样一段代码。打印try again的地址是804860A,所以设置avoid的地址是804860A,另外因为在将good job放在栈后,就跳转到了804861A。所以盲猜打印good job的地址为804861A。

最后也非常的amazing,竟然又给我蒙对了。
在这里插入图片描述

02_angr_find_condition

能够搜索到达某个指令的状态虽然很有用,但是在某些情况瞎,我们可能无法知道某个特定指令的地址(比如我这个菜鸡就不会熟练使用ida)。这个例子里就是教我们如何找到一个打印Good Job.的状态。这里改动的代码在is_successful(state)should_abort(state)这两个函数的返回语句处。主要思想就是当判断输出的值是否有Good Job. ,有的话就是成功了,否则如果是Try Again就需要终止。

这样就减少了打开IDA去分析指令地址的步骤,实现了自动化逆向的过程,很赞!

# It is very useful to be able to search for a state that reaches a certain
# instruction. However, in some cases, you may not know the address of the
# specific instruction you want to reach (or perhaps there is no single
# instruction goal.) In this challenge, you don't know which instruction
# grants you success. Instead, you just know that you want to find a state where
# the binary prints "Good Job."
#
# Angr is powerful in that it allows you to search for a states that meets an
# arbitrary condition that you specify in Python, using a predicate you define
# as a function that takes a state and returns True if you have found what you
# are looking for, and False otherwise.

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  # Define a function that checks if you have found the state you are looking
  # for.
  def is_successful(state):
    # Dump whatever has been printed out by the binary so far into a string.
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    # Return whether 'Good Job.' has been printed yet.
    # (!)
    return state.solver.is_true("Good Job." in str(stdout_output))  # :boolean

  # Same as above, but this time check if the state should abort. If you return
  # False, Angr will continue to step the state. In this specific challenge, the
  # only time at which you will know you should abort is when the program prints
  # "Try again."
  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    
    return state.solver.is_true("Try again." in str(stdout_output))  # :boolean

  # Tell Angr to explore the binary and find any state that is_successful identfies
  # as a successful state by returning True.
  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]
    print (solution_state.posix.dumps(sys.stdin.fileno()))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

结果自然也让我非常amazing!solved!

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

破落之实

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值