├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── arbiter ├── __init__.py ├── master_chief │ ├── __init__.py │ ├── sa_advanced.py │ ├── sa_base.py │ ├── sa_recon.py │ └── symbolic_execution.py ├── target.py └── utils.py ├── dataset ├── binary_stats.zip ├── debian_list ├── juliet_testcases.zip └── package_list ├── examples ├── README.md ├── cve-binaries │ ├── cve-2018-10388 │ ├── cve-2022-26495 │ └── cve-XXXX-YYYY ├── cve-logs │ ├── README.md │ ├── cve-2018-10388 │ │ ├── DDA.json │ │ ├── Recon.json │ │ ├── UCSE.json │ │ └── arbiter_vd_cve-2018-10388_cve-2018-10388.log │ ├── cve-2022-26495 │ │ ├── DDA.json │ │ ├── Recon.json │ │ ├── UCSE.json │ │ └── arbiter_vd_cve-2022-26495_cve-2022-26495.log │ └── cve-xxxx-yyyy │ │ ├── DDA.json │ │ ├── Recon.json │ │ ├── UCSE.json │ │ └── arbiter_vd_cve-xxxx-yyyy_cve-XXXX-YYYY.log └── cve-vuln_templates │ ├── vd_cve-2018-10388.py │ ├── vd_cve-2022-26495.py │ └── vd_cve-xxxx-yyyy.py ├── overview.png ├── setup.py ├── test_files ├── README.md ├── test.c └── test_arbiter.py └── vuln_templates ├── CWE131.py ├── CWE134.py ├── CWE190_juliet_signed.py ├── CWE190_juliet_unsigned.py ├── CWE252.py ├── CWE337.py ├── CWE680_juliet.py ├── README.md ├── kubernetes_wrapper.sh ├── run_arbiter.py └── syscalls_annotated.json /.gitignore: -------------------------------------------------------------------------------- 1 | arbiter.egg-info/ 2 | build/ 3 | logs/ 4 | dist/ 5 | **/__pycache__ 6 | *.elf 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN dpkg --add-architecture i386 4 | RUN apt update && apt -y upgrade 5 | RUN apt install -y python3-dev python3-pip build-essential sudo 6 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 7 | 8 | RUN useradd -m test && adduser test sudo 9 | RUN echo "test ALL=(ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers 10 | 11 | COPY arbiter /home/test/arbiter 12 | COPY vuln_templates /home/test/vuln_templates 13 | COPY setup.py /home/test/setup.py 14 | COPY README.md /home/test/ 15 | RUN chown -R test:test /home/test/ 16 | USER test 17 | RUN pip3 install --user angr python-json-logger 18 | RUN mkdir /home/test/logs 19 | RUN mkdir /home/test/bins 20 | WORKDIR /home/test 21 | RUN python3 /home/test/setup.py install --user 22 | CMD ["/bin/bash"] 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jayakrishna Menon V 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PWD ?= pwd_unknown 2 | NS ?= ghcr.io/jkrshnmenon/arbiter 3 | IMAGE_NAME ?= $(notdir $(PWD)) 4 | TAG ?= latest 5 | CONTAINER_NAME ?= default_instance 6 | 7 | .PHONY: help build release shell exec commit run 8 | 9 | help: 10 | @echo '' 11 | @echo 'Usage: make [TARGET] [EXTRA_ARGUMENTS]' 12 | @echo 'Targets:' 13 | @echo ' build build docker image $(NS)/$(IMAGE_NAME):$(TAG)' 14 | @echo ' release push docker image $(NS)/$(IMAGE_NAME):$(TAG)' 15 | @echo ' shell debug docker container for image $(NS)/$(IMAGE_NAME):$(TAG) as $(CONTAINER_NAME)' 16 | @echo ' exec run docker container for image $(NS)/$(IMAGE_NAME):$(TAG) as $(CONTAINER_NAME)' 17 | @echo ' commit build and push docker image $(NS)/$(IMAGE_NAME):$(TAG)' 18 | @echo ' run build and run docker image $(NS)/$(IMAGE_NAME):$(TAG) as $(CONTAINER_NAME)' 19 | @echo '' 20 | @echo 'Extra arguments:' 21 | @echo 'TAG=: make TAG="" (defaults to latest)' 22 | @echo 'IMAGE_NAME=: make IMAGE_NAME="" (defaults to directory name)' 23 | @echo 'CONTAINER_NAME=:make CONTAINER_NAME="" (defaults to "default_instance")' 24 | 25 | 26 | build: 27 | # test_scripts/update_image.sh $(TAG) 28 | docker build -t $(NS)/$(IMAGE_NAME):$(TAG) . 29 | 30 | release: 31 | docker push $(NS)/$(IMAGE_NAME):$(TAG) 32 | 33 | shell: build 34 | docker run --rm --name $(CONTAINER_NAME) -it $(NS)/$(IMAGE_NAME):$(TAG) /bin/bash 35 | 36 | debug: build 37 | docker run --rm -v $(PWD):/home/test/ --name $(CONTAINER_NAME) -it $(NS)/$(IMAGE_NAME):$(TAG) /bin/bash 38 | 39 | exec: 40 | docker run --rm --name $(CONTAINER_NAME) -it $(NS)/$(IMAGE_NAME):$(TAG) 41 | 42 | commit: build release 43 | 44 | run: build shell 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arbiter 2 | 3 | Arbiter is a combination of static and dynamic analyses, built on top of angr, that can be used to detect some vulnerability classes. 4 | 5 | All you need to use Arbiter is a sink that can be identified statically (like a call to a specific function), and a property that should not be violated at this sink. 6 | Arbiter can then be used to detect if this property is violated at any of the corresponding sinks in the binary. 7 | 8 | 9 | # Overview 10 | overview image 11 | 12 | 13 | # Research paper 14 | We present our approach and the findings of this work in the following research paper: 15 | 16 | **Arbiter: Bridging the Static and Dynamic Divide in Vulnerability Discovery on Binary Programs** 17 | 18 | Jayakrishna Vadayath, Moritz Eckert, Kyle Zeng, Nicolaas Weideman, Gokulkrishna Praveen Menon, Yanick Fratantonio, Davide Balzarotti, Adam Doupé, Tiffany Bao, Ruoyu Wang, Christophe Hauser and Yan Shoshitaishvili 19 | 20 | *In Proceedings of USENIX Security Symposium August 2022,* 21 | 22 | If you use Arbiter in a scientific publication, we would appreciate citations using the following **Bibtex** entry: 23 | 24 | ``` 25 | @inproceedings {vadayath_arbiter_22, 26 | title = {{Arbiter: Bridging the Static and Dynamic Divide in Vulnerability Discovery on Binary Programs}}, 27 | author = {Vadayath, Jayakrishna and Eckert, Moritz and Zeng, Kyle and Weideman, Nicolaas and Menon, Gokulkrishna Praveen and Fratantonio, Yanick and Balzarotti, Davide and Doup{\'e}, Adam and Bao, Tiffany and Wang, Ruoyu and Hauser, Christophe and Shoshitaishvili, Yan} 28 | booktitle = {31st USENIX Security Symposium (USENIX Security 22)}, 29 | month = aug, 30 | year = 2022, 31 | address = {Boston, MA}, 32 | } 33 | ``` 34 | 35 | 36 | [Paper](https://jkrshnmenon.github.io/assets/pdf/arbiter_paper.pdf) 37 | 38 | 39 | [Slides](https://jkrshnmenon.github.io/assets/pdf/arbiter_slides.pdf) 40 | 41 | 42 | # Installation 43 | 44 | `python setup.py build && python setup.py install` 45 | 46 | 47 | # Docker image 48 | 49 | `docker pull 4rbit3r/arbiter:latest` 50 | 51 | 52 | # Arbiter examples 53 | 54 | This repository contains some examples of using Arbiter to detect different CWE types in the `examples` directory. 55 | 56 | 57 | It also contains templates that were used for evaluating Arbiter on the Juliet Test suite as well as real world binaries in the `vuln_templates` directory. 58 | -------------------------------------------------------------------------------- /arbiter/__init__.py: -------------------------------------------------------------------------------- 1 | from .master_chief import * 2 | from .utils import FatalError 3 | -------------------------------------------------------------------------------- /arbiter/master_chief/__init__.py: -------------------------------------------------------------------------------- 1 | from .sa_recon import SA_Recon 2 | from .sa_advanced import SA_Adv 3 | from .symbolic_execution import SymExec 4 | -------------------------------------------------------------------------------- /arbiter/master_chief/sa_advanced.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import time 4 | import angr 5 | import logging 6 | from tqdm import tqdm 7 | from ..utils import Utils, FatalError, DataDependencyError, ConstantDataError 8 | from ..target import SA2_Target 9 | from angr.sim_options import refs 10 | from .sa_base import StaticAnalysis 11 | 12 | logger = logging.getLogger(name=__name__) 13 | 14 | 15 | class SA_Adv(StaticAnalysis): 16 | def __init__(self, sa_recon, checkpoint={}, require_dd=True, call_depth=1, json_dir=None): 17 | ''' 18 | :param sa_recon: The StaticAnalysisRecon object 19 | :param checkpoint A dictionary that maps a function name to the 20 | variable that ends up being used in the sink 21 | [0 for return value and 1-n for arguments] 22 | ''' 23 | self.sa_recon = sa_recon 24 | super(SA_Adv, self).__init__(sa_recon.project) 25 | 26 | self._statistics = {} 27 | 28 | self._checkpoint = {} 29 | for x in checkpoint: 30 | name = x 31 | if x.startswith("SYS_"): 32 | name = x[len("SYS_"):] 33 | logger.info("Converting %s to %s" % (x, name)) 34 | self._checkpoint[name] = checkpoint[x] 35 | 36 | self.map = sa_recon.map 37 | self._cfg = sa_recon.cfg 38 | self._targets = sa_recon.targets 39 | self._require_dd = require_dd 40 | self._call_depth = call_depth 41 | self._verbose = True if json_dir is not None else False 42 | self._json_dir = json_dir 43 | 44 | self._statistics['identified_functions'] = len(self._targets) 45 | if len(self._targets) <= 0: 46 | self._dump_stats() 47 | raise FatalError("No targets for SA advanced") 48 | 49 | self._final_targets = [] 50 | 51 | def __str__(self): 52 | return f"SA_Adv(project={self._project}, checkpoint={self._checkpoint}, targets={len(self.targets)})" 53 | 54 | @property 55 | def sinks(self): 56 | return self.map.keys() 57 | 58 | @property 59 | def targets(self): 60 | return self._final_targets 61 | 62 | def _dump_stats(self): 63 | ''' 64 | Print some numbers about this step of the analysis 65 | Should be invoked only after analyze_all 66 | ''' 67 | if not self._verbose: 68 | return 69 | 70 | with open(f'{self._json_dir}/DDA.json', 'w') as f: 71 | json.dump(self._statistics, f, indent=2) 72 | 73 | def get_slice_target(self, node, target): 74 | site = target.cfg.get_any_node(node.bbl) 75 | 76 | arg = node.sz 77 | 78 | return site, self.get_target_ins(site, arg) 79 | 80 | def _is_bp_write(self, target, bbl, idx): 81 | b = target.cfg.get_any_node(bbl).block 82 | stmt = b.vex.statements[idx] 83 | if self.utils.is_reg_write(stmt) is False: 84 | return False 85 | return self.utils.target_reg(stmt) == self.utils.name_to_vex('bp') 86 | 87 | def _parse_binop(self, stmt): 88 | treg = None 89 | val = 0 90 | for x in stmt.args: 91 | if self.utils.is_const(x): 92 | val = self.utils.target_const(x) 93 | elif self.utils.is_tmp_read(x): 94 | treg = self.utils.target_tmp(x) 95 | return treg, val 96 | 97 | def _find_tmp_write(self, treg, block, whitelist): 98 | ''' 99 | This depends heavily on VEX 100 | Assumes that a temporary register will not be initialised outside a 101 | block in which it is used 102 | ''' 103 | retval = None 104 | for idx in whitelist[::-1]: 105 | stmt = block.vex.statements[idx] 106 | if self.utils.is_tmp_write(stmt) is False: 107 | continue 108 | if self.utils.target_tmp(stmt) == treg: 109 | retval = idx 110 | assert retval is not None 111 | return retval 112 | 113 | def _find_reg_write(self, reg, block, whitelist): 114 | retval = None 115 | for idx in whitelist[::-1]: 116 | stmt = block.vex.statements[idx] 117 | if self.utils.is_reg_write(stmt) is False: 118 | continue 119 | if self.utils.target_reg(stmt) == reg: 120 | retval = self.utils.target_tmp(stmt.data) 121 | break 122 | 123 | if retval is not None: 124 | return self._find_tmp_write(retval, block, 125 | whitelist[:whitelist.index(idx)]) 126 | 127 | def _find_tmp_store(self, treg, block, whitelist): 128 | retval = None 129 | for idx in whitelist[::-1]: 130 | stmt = block.vex.statements[idx] 131 | if self.utils.is_tmp_store(stmt) is False: 132 | continue 133 | if self.utils.target_tmp(stmt.addr) == treg: 134 | retval = self.utils.target_tmp(stmt.data) 135 | break 136 | 137 | if retval is not None: 138 | return self._find_tmp_write(retval, block, 139 | whitelist[:whitelist.index(idx)]) 140 | 141 | def _handle_tmp_store(self, rhs, block, whitelist): 142 | if self.utils.is_const(rhs): 143 | raise ConstantDataError("Got constant value") 144 | treg = self.utils.target_tmp(rhs) 145 | return self._find_tmp_write(treg, block, whitelist) 146 | 147 | def _handle_reg_write(self, rhs, block, whitelist): 148 | if self.utils.is_const(rhs): 149 | raise ConstantDataError("Got constant value") 150 | treg = self.utils.target_tmp(rhs) 151 | return self._find_tmp_write(treg, block, whitelist) 152 | 153 | def _handle_tmp_write(self, rhs, block, whitelist): 154 | ''' 155 | Three cases here 156 | 1) tmp_reg1 = func(tmp_reg2) ; binop/unop 157 | 2) tmp_reg1 = load(tmp_reg2) 158 | 3) tmp_reg1 = GET(asm_reg) 159 | ''' 160 | retval = None 161 | flag = False 162 | if self.utils.is_tmp_unop(rhs): 163 | flag = True 164 | if self.utils.is_const(rhs.args[0]): 165 | retval = None 166 | else: 167 | retval = self.utils.target_tmp(rhs.args[0]) 168 | elif self.utils.is_tmp_binop(rhs): 169 | flag = True 170 | retval = None 171 | for x in rhs.args: 172 | if self.utils.is_tmp_read(x): 173 | retval = self.utils.target_tmp(x) 174 | break 175 | elif self.utils.is_tmp_read(rhs): 176 | retval = self.utils.target_tmp(rhs) 177 | elif self.utils.is_ite(rhs): 178 | if self.utils.is_tmp_read(rhs.iftrue): 179 | retval = self.utils.target_tmp(rhs.iftrue) 180 | elif self.utils.is_tmp_read(rhs.iffalse): 181 | retval = self.utils.target_tmp(rhs.iffalse) 182 | 183 | if retval is not None: 184 | return self._find_tmp_write(retval, block, whitelist) 185 | elif flag is True: 186 | raise ConstantDataError("Got constant value") 187 | 188 | if self.utils.is_reg_read(rhs): 189 | retval = self._find_reg_write(self.utils.target_reg(rhs), block, 190 | whitelist) 191 | elif self.utils.is_tmp_load(rhs): 192 | retval = self._find_tmp_store(self.utils.target_tmp(rhs.addr), 193 | block, 194 | whitelist) 195 | 196 | return retval 197 | 198 | def _handle_binop(self, rhs, block, whitelist): 199 | offset = 0 200 | treg, val = self._parse_binop(rhs) 201 | if self.utils.is_add(rhs): 202 | if val > 2 ** (self.utils.arch.bits - 2): 203 | val = -1 * ((2 ** self.utils.arch.bits) - val) 204 | offset += val 205 | elif self.utils.is_sub(rhs): 206 | if val > 2 ** (self.utils.arch.bits - 2): 207 | val = ((2 ** self.utils.arch.bits) - val) 208 | else: 209 | val = -1 * val 210 | offset += val 211 | else: 212 | pass 213 | return self._find_tmp_write(treg, block, whitelist), offset 214 | 215 | def _handle_unop(self, rhs, block, whitelist): 216 | treg = self.utils.target_tmp(rhs.args[0]) 217 | return self._find_tmp_write(treg, block, whitelist) 218 | 219 | def _track_stack(self, stmt, target, cur_block): 220 | ''' 221 | If we've reached here, it means that there was a load stmt without 222 | a corresponding store. 223 | It happens when an argument is passed via the stack 224 | Or when you pass a pointer as an argument 225 | ''' 226 | b = target.cfg.get_any_node(cur_block).block 227 | acfg = target._bs.annotated_cfg() 228 | whitelist = acfg.get_whitelisted_statements(cur_block) 229 | idx = None 230 | for x in whitelist: 231 | tstmt = b.vex.statements[x] 232 | if self.utils.is_imark(tstmt): 233 | continue 234 | if tstmt.data == stmt: 235 | idx = x 236 | break 237 | idx = self._find_tmp_write(self.utils.target_tmp(stmt.addr), b, 238 | whitelist[:whitelist.index(idx)]) 239 | filtered = whitelist[:whitelist.index(idx)+1] 240 | offset = 0 241 | while len(filtered) > 0: 242 | cur_idx = filtered.pop() 243 | cur_stmt = b.vex.statements[cur_idx] 244 | 245 | assert self.utils.is_tmp_write(cur_stmt) 246 | 247 | if self.utils.is_tmp_binop(cur_stmt.data): 248 | next_idx, val = self._handle_binop(cur_stmt.data, b, 249 | filtered) 250 | offset += val 251 | elif self.utils.is_reg_read(cur_stmt.data): 252 | reg = self.utils.target_reg(cur_stmt.data) 253 | return offset, b.addr, cur_idx 254 | elif self.utils.is_tmp_load(cur_stmt.data): 255 | return offset, b.addr, cur_idx 256 | elif self.utils.is_tmp_read(cur_stmt.data): 257 | next_idx = self._handle_tmp_write(cur_stmt.data, b, 258 | filtered) 259 | elif self.utils.is_tmp_unop(cur_stmt.data): 260 | next_idx = self._handle_unop(cur_stmt.data, b, 261 | filtered) 262 | else: 263 | raise angr.AngrAnalysisError("This should not have happened") 264 | 265 | filtered = filtered[:filtered.index(next_idx)+1] 266 | 267 | def _filter_preds(self, block, idx, target): 268 | rhs = block.vex.statements[idx].data 269 | dnode = target.get_any_ddg_node(block.addr, idx) 270 | preds = list(target.ddg.data_graph.predecessors(dnode)) 271 | 272 | if self.utils.is_reg_read(rhs): 273 | treg = self.utils.target_reg(rhs) 274 | if treg == self.utils.ret_reg: 275 | sim_proc = None 276 | for node in preds: 277 | if node.location.sim_procedure is not None: 278 | sim_proc = node 279 | # break here ?? 280 | if sim_proc is not None: 281 | # This sim_proc should've been called from the preceding 282 | # bbl. Change my mind. 283 | name = sim_proc.location.sim_procedure.display_name 284 | if type(target.source) == int: 285 | arg = self.utils.misc_src(name) 286 | prev = target.prev_block(block.addr) 287 | site = target.cfg.get_any_node(prev) 288 | return prev, self.get_target_ins(site, arg) 289 | else: 290 | if name in target.source: 291 | # Reached the return value of the checkpoint 292 | return None, None 293 | else: 294 | try: 295 | arg = self.utils.misc_src(name) 296 | except KeyError: 297 | raise DataDependencyError("Return value belongs to a different sim_proc") 298 | 299 | prev = target.prev_block(block.addr) 300 | site = target.cfg.get_any_node(prev) 301 | return prev, self.get_target_ins(site, arg) 302 | 303 | for node in preds: 304 | stmt = target.stmt_from_ddg_node(node) 305 | taddr, tidx = node.location.block_addr, node.location.stmt_idx 306 | if self.utils.is_reg_write(stmt) is False: 307 | continue 308 | elif taddr > block.addr: 309 | continue 310 | elif taddr == block.addr and tidx >= idx: 311 | continue 312 | elif self.utils.target_reg(stmt) == treg: 313 | return node.location.block_addr, node.location.stmt_idx 314 | 315 | elif self.utils.is_tmp_load(rhs): 316 | flag = False 317 | retval = None 318 | for node in preds: 319 | stmt = target.stmt_from_ddg_node(node) 320 | taddr, tidx = node.location.block_addr, node.location.stmt_idx 321 | if self.utils.is_tmp_store(stmt): 322 | flag = True 323 | if taddr < block.addr: 324 | retval = (taddr, tidx) 325 | break 326 | elif taddr == block.addr and tidx < idx: 327 | retval = (taddr, tidx) 328 | break 329 | 330 | if retval is not None: 331 | if type(target.source) == int: 332 | return retval 333 | 334 | call_sites = [x for x in target.get_call_sites() if x < block.addr] 335 | callees = {x: self._callee_name(x) for x in call_sites} 336 | 337 | matches = [] 338 | for x in target.source: 339 | matches += list(filter(lambda y: x in y, callees)) 340 | 341 | if len(matches) == 0: 342 | return retval 343 | 344 | if flag is True: 345 | # Couldn't find a correct store stmt 346 | # Track the address of the store 347 | acfg = target._bs.annotated_cfg() 348 | whitelist = acfg.get_whitelisted_statements(block.addr) 349 | filtered = whitelist[:whitelist.index(idx)] 350 | treg = self.utils.target_tmp(rhs.addr) 351 | return block.addr, self._find_tmp_write(treg, block, filtered) 352 | 353 | return None, None 354 | 355 | def _step_block(self, target, bbl, idx): 356 | acfg = target._bs.annotated_cfg() 357 | whitelist = acfg.get_whitelisted_statements(bbl) 358 | assert idx in whitelist 359 | 360 | filtered = whitelist[:whitelist.index(idx)+1] 361 | 362 | while len(filtered) > 0: 363 | cur_idx = filtered.pop() 364 | cur_block = target.cfg.get_any_node(bbl).block 365 | cur_stmt = cur_block.vex.statements[cur_idx] 366 | 367 | if self.utils.is_reg_write(cur_stmt): 368 | next_idx = self._handle_reg_write(cur_stmt.data, cur_block, 369 | filtered) 370 | elif self.utils.is_tmp_write(cur_stmt): 371 | next_idx = self._handle_tmp_write(cur_stmt.data, 372 | cur_block, 373 | filtered) 374 | if next_idx is None: 375 | bbl, idx = self._filter_preds(cur_block, cur_idx, target) 376 | 377 | return bbl, idx, cur_stmt.data 378 | 379 | elif self.utils.is_tmp_store(cur_stmt): 380 | next_idx = self._handle_tmp_store(cur_stmt.data, 381 | cur_block, 382 | filtered) 383 | 384 | filtered = filtered[:filtered.index(next_idx)+1] 385 | 386 | logger.info("This should never be printed") 387 | 388 | def _find_source(self, target, node): 389 | tslice = self.get_slice_target(node, target) 390 | 391 | if tslice[1] is None: 392 | # Could not find vex stmt 393 | if node.callee == "EOF": 394 | prev = target.prev_block(node.bbl) 395 | while prev not in target.func.get_call_sites(): 396 | # There should be a call site in this function 397 | # So, this shouldn't result in an infinite loop 398 | try: 399 | prev = target.prev_block(prev) 400 | except IndexError: 401 | raise DataDependencyError("No call sites found") 402 | 403 | if self._callee_name(target.func, prev) in target.source: 404 | # 0 indicates that the source is the return value of some sim_proc 405 | target._nodes[node.bbl].source = 0 406 | else: 407 | raise DataDependencyError("Could not find data dependency") 408 | else: 409 | raise angr.AngrAnalysisError("Could not find target instruction") 410 | 411 | target._bs = self._project.analyses.BackwardSlice(target.cfg, 412 | target.cdg, 413 | target.ddg, 414 | targets=[tslice]) 415 | 416 | cur_block, cur_idx = tslice[0].addr, tslice[1] 417 | source = None 418 | off = 0 419 | 420 | while True: 421 | x, y, z = self._step_block(target, 422 | cur_block, 423 | cur_idx) 424 | if x is None: 425 | assert y is None 426 | if self.utils.is_reg_read(z): 427 | treg = self.utils.target_reg(z) 428 | if treg == self.utils.name_to_vex('sp'): 429 | if self._is_bp_write(target, cur_block, cur_idx): 430 | off -= self.utils.arch.bytes 431 | source = off / self.utils.arch.bytes 432 | if self.utils.arch.bytes == 8: 433 | source += 6 434 | break 435 | source = self.utils.reg_to_arg(self.utils.target_reg(z)) 436 | break 437 | elif self.utils.is_tmp_load(z): 438 | off, cur_block, cur_idx = self._track_stack(z, target, 439 | cur_block) 440 | continue 441 | else: 442 | raise angr.AngrAnalysisError("New situation. Handle it") 443 | 444 | cur_block, cur_idx = x, y 445 | 446 | target._nodes[node.bbl].source = source 447 | logger.info("Found source at arg num : %d" % node.source) 448 | 449 | def _prepare_target(self, sa1): 450 | my_kb = angr.knowledge_base.KnowledgeBase(self._project, None) 451 | self._statistics[sa1.addr] = {'sink_count': len(sa1._nodes)} 452 | 453 | logger.debug("Creating CFGEmulated for function @ 0x%x" % sa1.addr) 454 | start_time = time.time() 455 | cfg = self._project.analyses.CFGEmulated(kb=my_kb, 456 | keep_state=True, 457 | starts=[sa1.addr], 458 | state_add_options=refs, 459 | call_depth=self._call_depth) 460 | end_time = time.time() 461 | self._statistics[sa1.addr]['cfg_creation'] = int(end_time - start_time) 462 | 463 | logger.debug("Creating DDG for function @ 0x%x (call_depth=%s)" % (sa1.addr, self._call_depth)) 464 | start_time = time.time() 465 | ddg = self._project.analyses.DDG(cfg, start=sa1.addr, call_depth=self._call_depth) 466 | end_time = time.time() 467 | self._statistics[sa1.addr]['ddg_creation'] = int(end_time - start_time) 468 | 469 | logger.debug("Creating CDG for function @ 0x%x" % sa1.addr) 470 | start_time = time.time() 471 | cdg = self._project.analyses.CDG(cfg, start=sa1.addr) 472 | end_time = time.time() 473 | self._statistics[sa1.addr]['cdg_creation'] = int(end_time - start_time) 474 | 475 | func = cfg.functions.function(sa1.addr) 476 | assert func is not None 477 | 478 | if len(self._checkpoint) != 0: 479 | names = [self._callee_name(func, x) for x in func.get_call_sites()] 480 | 481 | all_matches = [] 482 | for x in self._checkpoint: 483 | all_matches += list(filter(lambda y: x in y, names)) 484 | 485 | self._statistics[sa1.addr]['sources'] = len(all_matches) 486 | 487 | if len(all_matches) == 0: 488 | logger.warn("No checkpoint present in function") 489 | if self._require_dd is True: 490 | raise angr.AngrCFGError() 491 | return 492 | 493 | self._statistics[sa1.addr]['constants'] = 0 494 | 495 | target_obj = SA2_Target(cfg, cdg, ddg, func) 496 | target_obj._nodes = sa1._nodes 497 | 498 | return target_obj 499 | 500 | def analyze_one(self, sa1): 501 | logger.debug("Analysis of function @ 0x%x" % sa1.addr) 502 | target = self._prepare_target(sa1) 503 | 504 | if len(self._checkpoint) == 0: 505 | # Start from function entry point 506 | target.source = target.addr 507 | else: 508 | # Filter down the checkpoints 509 | func = target.func 510 | checkpoints = self._checkpoint.copy() 511 | names = [self._callee_name(func, x) for x in func.get_call_sites()] 512 | for x in checkpoints.copy(): 513 | if x not in names: 514 | checkpoints.pop(x) 515 | if len(checkpoints) == 0: 516 | # Default to function entry 517 | target.source = target.addr 518 | else: 519 | target.source = checkpoints 520 | 521 | filtered_checkpoints = {} 522 | for x in checkpoints.copy(): 523 | for y in names: 524 | if x in y: 525 | filtered_checkpoints[y] = self._checkpoint[x] 526 | 527 | target.source = filtered_checkpoints if len(filtered_checkpoints) > 0 else target.addr 528 | 529 | for n in target.nodes: 530 | logger.debug("Starting back tracking for 0x%x" % n) 531 | try: 532 | self._find_source(target, target._nodes[n]) 533 | except angr.AngrAnalysisError as e: 534 | logger.error(e) 535 | target.remove(n) 536 | continue 537 | except DataDependencyError as e: 538 | if target.sink_name(n) == "EOF" and self._require_dd is True: 539 | logger.error(e) 540 | target.remove(n) 541 | continue 542 | except ConstantDataError as e: 543 | self._statistics[sa1.addr]['constants'] += 1 544 | logger.error(e) 545 | target.remove(n) 546 | continue 547 | except (KeyError, TypeError, AssertionError) as e: 548 | target._nodes[n].source = -1 549 | continue 550 | except AttributeError as e: 551 | target._nodes[n].source = -1 552 | 553 | 554 | if target.flag is False: 555 | logger.info("No valid sinks in function @ 0x%x" % target.addr) 556 | else: 557 | logger.info("%d sinks in function @ 0x%x" % (target.node_count, 558 | target.addr)) 559 | 560 | self._dump_stats() 561 | return target 562 | 563 | def analyze_all(self): 564 | for x in tqdm(self._targets, desc="Analyzing targets"): 565 | try: 566 | obj = self.analyze_one(x) 567 | if obj.flag is True: 568 | self._final_targets.append(obj) 569 | else: 570 | del obj 571 | except (angr.AngrCFGError, angr.errors.SimEngineError) as e: 572 | logger.error(e) 573 | continue 574 | except (KeyError, TypeError, StopIteration, OverflowError, MemoryError) as e: 575 | logger.error(e) 576 | continue 577 | 578 | self._dump_stats() 579 | -------------------------------------------------------------------------------- /arbiter/master_chief/sa_base.py: -------------------------------------------------------------------------------- 1 | import angr 2 | import logging 3 | from ..utils import Utils 4 | from ..target import * 5 | 6 | 7 | class StaticAnalysis(object): 8 | ''' 9 | The base class for the static analysis. 10 | This class just contains a couple of functions which are used by both the 11 | basic and advanced static analysis 12 | ''' 13 | def __init__(self, p): 14 | self._targets = [] 15 | self._project = p 16 | self.utils = Utils(p) 17 | 18 | @property 19 | def cfg(self): 20 | return self._cfg 21 | 22 | @property 23 | def project(self): 24 | return self._project 25 | 26 | @property 27 | def targets(self): 28 | return self._targets 29 | 30 | def _callee_name(self, func, site): 31 | callee = func.get_call_target(site) 32 | 33 | if callee is None: 34 | raise angr.AngrCFGError("Couldn't find call target @ %x" % site) 35 | 36 | target = self.cfg.functions.function(callee) 37 | 38 | if target is None: 39 | raise angr.AngrCFGError("Couldn't find function @ %x" % callee) 40 | 41 | return target.demangled_name 42 | 43 | def _find_ret_block(self, func): 44 | ''' 45 | Return BBL that contains the ret instruction 46 | ''' 47 | for addr in func.block_addrs_set: 48 | node = self.cfg.get_any_node(addr) 49 | if node is None: 50 | return None 51 | block = node.block 52 | if block is None: 53 | return None 54 | if self._find_ret_ins(block) is not None: 55 | return addr 56 | 57 | def _find_ret_ins(self, block): 58 | ''' 59 | Return addr of ret instruction 60 | Hopefully the last instruction should be the ret 61 | ''' 62 | last_ins = block.capstone.insns[-1] 63 | if last_ins.insn.mnemonic == 'ret': 64 | return last_ins.insn.address 65 | 66 | return None 67 | 68 | def get_target_ins(self, bbl, arg_num, flag=False): 69 | ''' 70 | Returns the address of the instruction which sets the argument arg_num 71 | ''' 72 | if self._project.arch.bits == 64: 73 | if arg_num == 0: 74 | reg = self.utils.ret_reg 75 | else: 76 | reg = self.utils.arg_to_offset(arg_num) 77 | 78 | return self.get_reg_populator(bbl, reg) 79 | 80 | elif self._project.arch.bits == 32: 81 | if arg_num == 0: 82 | return self.get_reg_populator(bbl, self.utils.ret_reg) 83 | 84 | return self.get_vex_id(bbl.block, 85 | self.get_arg_populator(bbl, arg_num), 86 | arg_num) 87 | 88 | def get_arg_populator(self, bbl, arg_num): 89 | block = bbl.block 90 | ins = block.capstone.insns[::-1] 91 | arg_ctr = 0 92 | ''' 93 | Iterate over instructions in the block in reverse. 94 | If argument counter == arg_num, return the address of the instruction 95 | For each push instruction, increment the argument counter. 96 | If instruction is `mov [esp+x], eax`, check if arg_num == arg_ctr + x/4 97 | ''' 98 | for tmp in ins: 99 | if tmp.insn.mnemonic == 'push': 100 | arg_ctr += 1 101 | if arg_num == arg_ctr: 102 | return tmp.insn.address 103 | continue 104 | 105 | if self.utils.store_in_stack(tmp) is True: 106 | ''' 107 | Assuming we're dealing with 32 bit, dividing offsets by 4 108 | should do 109 | ''' 110 | disp = self.utils.disp(tmp) 111 | if arg_num == arg_ctr + disp/4 + 1: 112 | return tmp.insn.address 113 | 114 | ''' 115 | Could not identify the correct instruction 116 | Different architecture maybe ? 117 | ''' 118 | raise angr.AngrAnalysisError("""Could not identify instruction which 119 | populates the target argument {} : {}""".format(hex(bbl), arg_num)) 120 | 121 | def get_reg_populator(self, bbl, reg): 122 | for x in bbl.block.vex.statements[::-1]: 123 | if self.utils.is_reg_write(x) is False: 124 | continue 125 | if self.utils.target_reg(x) != reg: 126 | continue 127 | return bbl.block.vex.statements.index(x) 128 | 129 | def get_vex_id(self, block, ins, arg): 130 | ''' 131 | Returns the vex ID of the statement populating the argument arg 132 | ''' 133 | if self._project.arch.bits == 64: 134 | reg = self.utils.arg_to_reg(arg) 135 | 136 | assert reg is not None 137 | 138 | return self.get_vex_for_reg(block, ins, reg) 139 | 140 | else: 141 | return self.get_vex_for_arg(block, ins, arg) 142 | 143 | def get_vex_for_reg(self, block, ins, reg): 144 | target_stmt = None 145 | 146 | statements = block.vex.statements 147 | 148 | reg_num = self.utils.name_to_vex(reg) 149 | 150 | for x in range(len(statements)): 151 | stmt = statements[x] 152 | if self.utils.is_imark(stmt) is False: 153 | continue 154 | if stmt.addr == ins: 155 | break 156 | 157 | for stmt in statements[x+1:]: 158 | if self.utils.is_imark(stmt): 159 | break 160 | if self.utils.is_reg_write(stmt) is False: 161 | continue 162 | if self.utils.target_reg(stmt) == reg_num: 163 | target_stmt = stmt 164 | break 165 | 166 | assert target_stmt is not None 167 | return statements.index(target_stmt) 168 | 169 | def get_vex_for_arg(self, block, ins, arg): 170 | ''' 171 | Push instructions and instructions of the form `mov [esp+x], {r/imm}` 172 | are translated into store instructions in VEX. 173 | All we need to do is to identify the store vex instruction that 174 | corresponds to the IMark ins 175 | ''' 176 | target_stmt = None 177 | statements = block.vex.statements 178 | 179 | for x in range(len(statements)): 180 | stmt = statements[x] 181 | if self.utils.is_imark(stmt) is False: 182 | continue 183 | if stmt.addr == ins: 184 | break 185 | ''' 186 | The required statment is the one which stores a value. 187 | ''' 188 | for stmt in statements[x+1:]: 189 | if self.utils.is_tmp_store(stmt): 190 | target_stmt = stmt 191 | break 192 | if self.utils.is_imark(stmt): 193 | break 194 | 195 | assert target_stmt is not None 196 | return statements.index(target_stmt) 197 | 198 | def _format_str_types(self, fmt): 199 | if fmt == '%s': 200 | return "i" 201 | else: 202 | return "v" 203 | 204 | def _push_regs(self, state): 205 | ''' 206 | In x64, the first 6 arguments are passed via regsiters. 207 | In order to maintain a similar method to retrieve these arguments, 208 | we'll push the registers in the reverse order to the stack 209 | ''' 210 | state.stack_push(state.regs.r9) 211 | state.stack_push(state.regs.r8) 212 | state.stack_push(state.regs.rcx) 213 | state.stack_push(state.regs.rdx) 214 | state.stack_push(state.regs.rsi) 215 | state.stack_push(state.regs.rdi) 216 | 217 | def _nth_arg(self, state, n, saved_pc=False): 218 | ''' 219 | Return the nth argument from the state 220 | We're only dealing with x86 and x64 here 221 | ''' 222 | if n == 0: 223 | name = self.utils.vex_to_name(self.utils.ret_reg, self.utils.arch.bytes) 224 | return getattr(state.regs, name) 225 | 226 | state_copy = state.copy() 227 | if saved_pc is True: 228 | _ = state_copy.stack_pop() 229 | 230 | if self._project.arch.bits == 64: 231 | self._push_regs(state_copy) 232 | 233 | for x in range(n - 1): 234 | state_copy.stack_pop() 235 | 236 | return state_copy.stack_pop() 237 | -------------------------------------------------------------------------------- /arbiter/master_chief/sa_recon.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | import angr 4 | import logging 5 | from tqdm import tqdm 6 | from ..target import SA1_Target 7 | from ..utils import FatalError 8 | from .sa_base import StaticAnalysis 9 | 10 | logger = logging.getLogger(name=__name__) 11 | 12 | 13 | class SA_Recon(StaticAnalysis): 14 | ''' 15 | A class which performs the basic static analysis 16 | Analyse the function at func_addr and search for calls to sinks 17 | ''' 18 | def __init__(self, p, sinks, maps={}, json_dir=None): 19 | ''' 20 | :param p: The angr Project instance 21 | :param sinks: A list of sinks to look for 22 | :param maps: A dictionary that maps the functions to the 23 | argument description as provided in utils.py 24 | ''' 25 | super(SA_Recon, self).__init__(p) 26 | 27 | self.map = {} 28 | self._statistics = {} 29 | self._verbose = True if json_dir is not None else False 30 | self._json_dir = json_dir 31 | 32 | for x in sinks: 33 | if x in maps.keys(): 34 | self.map[x] = maps[x] 35 | elif x in self.utils.func_map.keys(): 36 | self.map[x] = self.utils.func_map[x] 37 | else: 38 | logger.error("I don't know the arguments for %s" % x) 39 | raise FatalError 40 | 41 | for x in self.map.keys(): 42 | if self._is_ret(self.map[x]): 43 | continue 44 | elif 'n' not in self.map[x]: 45 | logger.error("""Please specify the argument to be tracked for \ 46 | the sinks %s by denoting it as `n`""" % x) 47 | elif self.map[x].count('n') > 1: 48 | logger.warn("Multiple arguments specified for sink %s" % x) 49 | logger.warn("Defaulting to use the first one") 50 | 51 | logger.debug("Creating CFG") 52 | start_time = time.time() 53 | try: 54 | self._cfg = self._project.analyses.CFG() 55 | except AttributeError: 56 | logger.error("Cannot create CFG") 57 | raise FatalError 58 | end_time = time.time() 59 | 60 | self._statistics['cfg_creation'] = int(end_time - start_time) 61 | self._statistics['cfg_blocks'] = len(self._cfg.graph.nodes()) 62 | self._statistics['cfg_edges'] = len(self._cfg.graph.edges()) 63 | self._statistics['recovered_functions'] = len(self._cfg.functions.items()) 64 | self._statistics['identified_functions'] = 0 65 | 66 | def __str__(self): 67 | return f"SA_Recon(project={self.project}, sinks={self.sinks}, maps={self.map}, targets={len(self.targets)})" 68 | 69 | def _dump_stats(self): 70 | ''' 71 | Print some numbers about this step of the analysis 72 | Should be invoked only after analyze 73 | ''' 74 | if not self._verbose: 75 | return 76 | 77 | with open(f'{self._json_dir}/Recon.json', 'w') as f: 78 | json.dump(self._statistics, f, indent=2) 79 | 80 | def _is_ret(self, arglist): 81 | return 'r' in arglist 82 | 83 | @property 84 | def sinks(self): 85 | return self.map.keys() 86 | 87 | def _check_callees(self, func, target, sinks): 88 | """ 89 | Check the `func` in the `target` for any call to any function name in set `sinks` 90 | """ 91 | 92 | for site in sorted(func.get_call_sites()): 93 | name = self._callee_name(func, site) 94 | 95 | for callee in sinks: 96 | if callee not in name: 97 | continue 98 | arglist = self.map[callee] 99 | 100 | if self._is_ret(arglist): 101 | logger.debug("Finding ret block for %s @ 0x%x" % (callee, site)) 102 | site = self._find_ret_block(func) 103 | if site is None: 104 | # No ret instruction 105 | continue 106 | 107 | target.add_node(site, None, self._cfg, arglist) 108 | 109 | def _check_sinks(self, func): 110 | target = SA1_Target(func) 111 | 112 | self._check_callees(func, target, self.sinks) 113 | 114 | if target.node_count > 0: 115 | self._targets.append(target) 116 | return True 117 | 118 | return False 119 | 120 | def analyze_one(self, identifier): 121 | func = None 122 | 123 | if isinstance(identifier, int): 124 | func = self._cfg.functions.function(identifier) 125 | addr = identifier 126 | elif isinstance(identifier, str): 127 | for a, f in self._cfg.functions.items(): 128 | if f.name == identifier: 129 | func = f 130 | addr = a 131 | break 132 | 133 | if func is None: 134 | logger.error("Could not find function for %s" % identifier) 135 | return 136 | 137 | logger.info("Starting recon of 0x%x" % addr) 138 | try: 139 | if self._check_sinks(func) is True: 140 | logger.debug('Adding target function %s:0x%x' % (func.name, 141 | addr)) 142 | except angr.AngrCFGError as e: 143 | logger.error(e) 144 | return 145 | 146 | def analyze(self, ignore_funcs=[]): 147 | for addr, func in tqdm(self._cfg.functions.items(), desc="Identifying functions"): 148 | if len(ignore_funcs) > 0: 149 | if addr in ignore_funcs or func.name in ignore_funcs: 150 | continue 151 | logger.info("Starting recon of 0x%x" % addr) 152 | try: 153 | if self._check_sinks(func) is True: 154 | logger.debug('Adding target function %s:0x%x' % (func.name, 155 | addr)) 156 | self._statistics['identified_functions'] += 1 157 | except angr.AngrCFGError as e: 158 | logger.error(e) 159 | continue 160 | 161 | self._dump_stats() 162 | -------------------------------------------------------------------------------- /arbiter/master_chief/symbolic_execution.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import time 4 | import angr 5 | import signal 6 | import claripy 7 | import logging 8 | import threading 9 | import networkx as nx 10 | 11 | from tqdm import tqdm 12 | from ..target import * 13 | from archinfo import Endness 14 | from .sa_base import StaticAnalysis 15 | from ..utils import Utils, FatalError 16 | from .sa_advanced import SA_Adv 17 | 18 | DEBUG = os.environ.get('DEBUG', False) 19 | logger = logging.getLogger(name=__name__) 20 | 21 | 22 | 23 | class SymExec(StaticAnalysis, DerefHook): 24 | ''' 25 | A class which performs symbolic execution on the target function. 26 | If the advanced static analysis was able to detect a source for the input, 27 | use that to create a state. 28 | ''' 29 | def __init__(self, sa, constrain, require_dd=None, json_dir=None): 30 | ''' 31 | :param sa :The SA_Adv object 32 | :param constrain :A function that takes in a state, the expression 33 | representing the argument and a list of expressions 34 | that influence the final expression. 35 | This function should apply the constraints on the 36 | list of expressions that indicate the presence of a 37 | bug 38 | :param require_dd :A boolean that tells Arbiter to discard situations 39 | without data dependency between initial and final 40 | expressions 41 | ''' 42 | self.sa = sa 43 | self.constrain = constrain 44 | super(SymExec, self).__init__(sa.project) 45 | self._targets = sa.targets 46 | self.sinks = sa.sinks 47 | self._cfg = sa.cfg 48 | self._require_dd = sa._require_dd if require_dd is None else require_dd 49 | self._verbose = True if json_dir is not None else False 50 | self._json_dir = json_dir 51 | 52 | self._statistics = {} 53 | self._stats_filename = 'UCSE.json' 54 | self._statistics['identified_functions'] = len(self._targets) 55 | 56 | self._watchdog_event = threading.Event() 57 | self._timeout_received = False 58 | 59 | if len(self._targets) <= 0: 60 | raise FatalError("No targets for SymExec") 61 | 62 | self._set_up_hooks() 63 | signal.signal(signal.SIGALRM, self._signal_handler) 64 | 65 | self.reports = {} 66 | 67 | def __str__(self): 68 | return f"SymExec(project={self._project}, targets={len(self.targets)}, reports={len(self.reports)})" 69 | 70 | @staticmethod 71 | def mem_derefs(state): 72 | if state.globals.get('derefs', 0) == 0: 73 | return [] 74 | else: 75 | return state.globals['derefs'] 76 | 77 | def _dump_stats(self): 78 | ''' 79 | Print some numbers about this step of the analysis 80 | Should be invoked only after run_all 81 | ''' 82 | if not self._verbose: 83 | return 84 | 85 | with open(f'{self._json_dir}/{self._stats_filename}', 'w') as f: 86 | json.dump(self._statistics, f, indent=2) 87 | 88 | def _watchdog(self, timeout): 89 | if DEBUG: 90 | return 91 | self._timeout_received = False 92 | logger.debug(f"Watchdog started, waiting for {timeout}s") 93 | # When we timeout, Event.wait will return False 94 | # If we don't timeout, Event.wait returns True 95 | if not self._watchdog_event.wait(timeout): 96 | while not self._timeout_received: 97 | logger.debug(f"Watchdog timed out, sending SIG_ALARM to self") 98 | os.kill(os.getpid(), signal.SIGALRM) 99 | time.sleep(1) 100 | 101 | def _hook_checkpoint(self, target, cname): 102 | cfunc = self.cfg.functions.get(cname) 103 | if cfunc is None: 104 | logger.warn(f"Could not hook checkpoint {cname}") 105 | return 106 | if self._project.is_hooked(cfunc.addr): 107 | return 108 | self._project.hook(cfunc.addr, CheckpointHook(kwargs={'arg_num': target.source[cname]})) 109 | logger.debug(f'Hooked checkpoint {cname}') 110 | 111 | def _set_up_hooks(self): 112 | self._project.hook_symbol('strlen', StrlenHook()) 113 | self._project.hook_symbol('strchr', StrchrHook()) 114 | self._project.hook_symbol('getenv', GetenvHook()) 115 | 116 | funcs = ['strdup', 'gettext', 'dcgettext', 'dgettext'] 117 | 118 | for x in funcs: 119 | self._project.hook_symbol(x, FirstArgHook()) 120 | 121 | def _set_up_bp(self, state): 122 | state.inspect.b('mem_read', when=angr.BP_AFTER, 123 | action=self._mem_read_hook) 124 | state.inspect.b('mem_write', when=angr.BP_BEFORE, 125 | action=self._mem_write_hook) 126 | 127 | return state 128 | 129 | def _signal_handler(self, signum, frame): 130 | logger.debug("Signal handler invoked") 131 | raise TimeoutException("Timeout", errors="Timed out") 132 | 133 | def _first_bbl(self, state): 134 | return list(state.history.bbl_addrs)[0] 135 | 136 | def _eliminate_false_positives(self, expr, init_val, state): 137 | # TODO : Generalize for all archs instead of just x64 138 | # The false positive occurs when all the bits in init_vals are not 139 | # present in the expr 140 | try: 141 | children = [x for x in set(expr.recursive_children_asts) if x.symbolic] 142 | except ClaripyOperationError: 143 | children = [] 144 | 145 | if len(children) <= 1: 146 | return 147 | 148 | for x in init_val: 149 | upper = 0 150 | flag = False 151 | for y in children[::-1]: 152 | if type(y) != claripy.ast.bv.BV: 153 | continue 154 | elif x.length == y.length: 155 | result = x == y 156 | if result.is_true(): 157 | flag = True 158 | continue 159 | elif self._find_child_in_list(y, [x]) is False: 160 | continue 161 | for z in range(y.length-1, 0, -1): 162 | idx = self._find_bit_in_ast(y[z], x) 163 | if idx is not None: 164 | upper = max(upper, idx) 165 | break 166 | if upper == self.project.arch.bits - 1: 167 | break 168 | elif upper == 0 and flag is True: 169 | upper = self.project.arch.bits - 1 170 | break 171 | elif upper >= self.project.arch.bits: 172 | upper = self.project.arch.bits - 1 173 | break 174 | if upper >= 32 and upper < 64: 175 | upper = 63 176 | elif upper >= 0 and upper < 32: 177 | upper = 31 178 | 179 | logger.debug("Max used bit : %d" % (upper+1)) 180 | state.solver.add(x <= 2**(upper+1) - 1) 181 | 182 | def _apply_sz_constraints(self, state, expr, site, obj): 183 | val = None 184 | init_val = state.globals.get('sym_vars') 185 | 186 | self._eliminate_false_positives(expr, init_val, state) 187 | 188 | s = self.constrain(state=state, expr=expr, init_val=init_val, site=site) 189 | if s is not None: 190 | state = s 191 | 192 | obj['sat_states'] = 0 193 | for x in init_val: 194 | try: 195 | val = state.solver.eval(x) 196 | logger.info("Satisfied state : 0x%x" % val) 197 | obj['sat_states'] += 1 198 | self._dump_stats() 199 | if site.bbl not in self.reports.keys(): 200 | self.reports[site.bbl] = Report(state, site) 201 | except angr.SimUnsatError: 202 | val = None 203 | logger.info("Got Unsat") 204 | 205 | if len(init_val) == 0: 206 | if state.satisfiable(): 207 | val = state.solver.eval(expr) 208 | logger.info("Satisfied state: 0x%x" % val) 209 | obj['sat_states'] += 1 210 | self._dump_stats() 211 | if site.bbl not in self.reports.keys(): 212 | self.reports[site.bbl] = Report(state, site) 213 | else: 214 | val = None 215 | logger.info("Got Unsat") 216 | 217 | return val is not None 218 | 219 | def _check_state(self, state, site, target=None, obj=None): 220 | if obj is None: 221 | assert target is not None 222 | obj = self._statistics[target.addr] 223 | 224 | sym_vars = state.globals.get('sym_vars', 0) 225 | obj['expressions_tracked'] = len(sym_vars) 226 | name = site.callee 227 | if name == "EOF": 228 | arg_num = [0] 229 | elif any([x for x in self.sinks if x in name]): 230 | arg_num = [site.sz] 231 | else: 232 | raise angr.AngrAnalysisError("New condition for %s" % name) 233 | 234 | assert len(arg_num) >= 1, "No args for %s" % name 235 | new_expr = None 236 | filtered_sym_vars = [] 237 | 238 | if target is not None: 239 | new_expr = target.expr_from_state(self._project, state, arg_num[0]) 240 | if new_expr is None: 241 | new_expr = self._nth_arg(state, arg_num[0]) 242 | 243 | if len(sym_vars) > 1: 244 | filtered_sym_vars = [] 245 | try: 246 | for child in list(set(new_expr.recursive_leaf_asts)): 247 | if self._find_in_list(child, sym_vars): 248 | filtered_sym_vars.append(child) 249 | except ClaripyOperationError: 250 | #TODO how to handle this ? 251 | pass 252 | if len(filtered_sym_vars) == 0 and self._require_dd is False: 253 | filtered_sym_vars = sym_vars 254 | else: 255 | # Double checking the result of SA_advanced 256 | # At least one of the leaf ast of new_expr should be in sym_vars 257 | if self._find_child_in_list(new_expr, sym_vars) is False: 258 | logger.warn("Couldn't find expression in sym vars") 259 | if self._require_dd is True: 260 | self._dump_stats() 261 | return 262 | 263 | filtered_sym_vars = sym_vars 264 | 265 | obj['filtered_expressions'] = len(filtered_sym_vars) 266 | 267 | state.globals['sym_vars'] = filtered_sym_vars 268 | 269 | logger.info("Applying constraints for sink : %s" % name) 270 | 271 | self._dump_stats() 272 | return self._apply_sz_constraints(state, new_expr, site, obj) 273 | 274 | def _explore_one(self, target, site, init_state): 275 | self._statistics[target.addr]['paths_found'] = 0 276 | self._statistics[target.addr]['paths_timedout'] = 0 277 | try: 278 | block = target.cfg.get_any_node(site.bbl).block 279 | except AttributeError: 280 | logger.warn("Could not find target sink") 281 | return 282 | name = site.callee 283 | 284 | if name == "EOF": 285 | init_state.globals['track_write'] = True 286 | pg = self._project.factory.simulation_manager(init_state) 287 | counter = 0 288 | start = time.time() 289 | logger.info("Starting exploration 0x%0x => 0x%0x" % (init_state.addr, site.bbl)) 290 | self._watchdog_event.clear() 291 | t = threading.Thread(target=self._watchdog, args=(300,)) 292 | t.start() 293 | # self._watchdog(300) 294 | try: 295 | pg.explore(find=sorted(block.instruction_addrs)[-1]) 296 | 297 | if len(pg.found) == 0: 298 | self._watchdog_event.set() 299 | t.join() 300 | raise angr.AngrAnalysisError("No paths found") 301 | 302 | if len(pg.active) == 0: 303 | logger.debug("Found %d paths; No active paths" % len(pg.found)) 304 | self._statistics[target.addr]['paths_found'] += len(pg.found) 305 | for pp in pg.found: 306 | self._watchdog_event.set() 307 | if self._check_state(pg.found[0], site, target) is True: 308 | logger.debug("Waiting for watchdog to join") 309 | t.join() 310 | return 311 | 312 | while len(pg.active) > 0 and counter < 3: 313 | logger.debug("Found %d paths; active paths remaining" % len(pg.found)) 314 | counter += len(pg.found) 315 | self._statistics[target.addr]['paths_found'] += len(pg.found) 316 | end = time.time() 317 | self._statistics[target.addr]['exploration_time'] = int(end - start) 318 | for pp in pg.found: 319 | if self._check_state(pp, site, target): 320 | self._watchdog_event.set() 321 | logger.debug("Waiting for watchdog to join") 322 | t.join() 323 | return 324 | pg.drop(stash='found') 325 | # signal.alarm(300) 326 | logger.debug("Wrapping up %d active paths" % len(pg.active)) 327 | pg.explore(find=sorted(block.instruction_addrs)[-1]) 328 | except (TimeoutException, KeyboardInterrupt) as e: 329 | self._watchdog_event.set() 330 | self._timeout_received = True 331 | logger.debug("Waiting for watchdog to join") 332 | t.join(timeout=1) 333 | logger.debug("Got an exception") 334 | self._statistics[target.addr]['paths_timedout'] += 1 335 | logger.error(e) 336 | except RecursionError as e: 337 | self._watchdog_event.set() 338 | logger.debug("Waiting for watchdog to join") 339 | t.join(timeout=1) 340 | logger.debug("Got an exception") 341 | logger.error(e) 342 | except: 343 | logger.debug("Got an exception") 344 | self._watchdog_event.set() 345 | logger.debug("Waiting for watchdog to join") 346 | t.join(timeout=1) 347 | 348 | end = time.time() 349 | logger.debug("Found %d paths" % len(pg.found)) 350 | self._statistics[target.addr]['exploration_time'] = int(end - start) 351 | self._statistics[target.addr]['paths_found'] += len(pg.found) 352 | for pp in pg.found: 353 | self._check_state(pp, site, target) 354 | 355 | self._watchdog_event.set() 356 | self._timeout_received = True 357 | logger.debug("Waiting for watchdog to join") 358 | t.join() 359 | del init_state 360 | del pg 361 | 362 | def _create_ret_states(self, target, name): 363 | sources = [] 364 | states = [] 365 | for x in target.func.get_call_sites(): 366 | if name == self._callee_name(target.func, x): 367 | return_addr = target.func.get_call_return(x) 368 | if return_addr == x: 369 | b = self.cfg.model.get_any_node(x).block 370 | sources.append(b.addr+b.size) 371 | else: 372 | sources.append(target.func.get_call_return(x)) 373 | logger.debug("Adding checkpoint address %s:0x%0x" % (name, sources[-1])) 374 | 375 | for addr in set(sources): 376 | s = self._project.factory.blank_state(addr=addr) 377 | expr = claripy.BVS('ret', self.utils.arch.bits) 378 | setattr(s.regs, self.utils.arch.register_names[self.utils.ret_reg], 379 | expr) 380 | s.globals['sym_vars'] = [expr] 381 | s.globals['derefs'] = [] 382 | states.append(self._set_up_bp(s)) 383 | 384 | return states 385 | 386 | def _create_checkpoint_states(self, target, name): 387 | sources = [] 388 | states = [] 389 | for x in target.func.get_call_sites(): 390 | if name == self._callee_name(target.func, x): 391 | bl = target.cfg.get_any_node(x) 392 | sources.append(sorted(bl.instruction_addrs)[-1]) 393 | logger.debug("Adding checkpoint address %s:0x%0x" % (name, sources[-1])) 394 | 395 | for addr in set(sources): 396 | s = self._project.factory.blank_state(addr=target.addr) 397 | sm = self._project.factory.simulation_manager(s) 398 | sm.explore(find=addr) 399 | states += sm.found 400 | 401 | for state in states: 402 | arg_num = target.source[name] 403 | expr = target.expr_from_state(self._project, state, arg_num) 404 | 405 | if expr is None: 406 | expr = self._nth_arg(state, arg_num) 407 | 408 | if len(list(expr.recursive_leaf_asts)) > 1: 409 | logger.info('Checkpoint parameter is a composite AST.') 410 | logger.info('This might lead to incorrect results.') 411 | 412 | state.globals['sym_vars'] = [expr] 413 | state.globals['derefs'] = [] 414 | self._set_up_bp(state) 415 | 416 | return states 417 | 418 | def _get_checkpoint_state(self, target, site): 419 | logger.debug("Creating checkpoint states for %s" % target.name) 420 | states = [] 421 | if not isinstance(target.source, dict): 422 | logger.debug("No checkpoint present") 423 | return states 424 | for x in target.source: 425 | if target.checkpoint_is_ret(x): 426 | states += self._create_ret_states(target, x) 427 | else: 428 | states += self._create_checkpoint_states(target, x) 429 | self._hook_checkpoint(target, x) 430 | 431 | logger.debug("Created %d states" % len(states)) 432 | return states 433 | 434 | def _create_entry_state(self, target, site): 435 | logger.debug("Creating initial state for %s" % target.name) 436 | sym_vars = [] 437 | if site.source is None: 438 | for x in range(10): 439 | sym_vars.append(claripy.BVS('var_'+str(x), 440 | self.utils.arch.bits)) 441 | init_state = self._project.factory.call_state(target.addr, 442 | *sym_vars) 443 | else: 444 | exprs = [] 445 | for x in range(site.source - 1): 446 | exprs.append(claripy.BVS('var_'+str(x), self.utils.arch.bits)) 447 | sym_vars = [claripy.BVS('src', self.utils.arch.bits)] 448 | init_state = self._project.factory.call_state(target.addr, 449 | *(exprs+sym_vars)) 450 | 451 | init_state.globals['sym_vars'] = sym_vars 452 | init_state.globals['derefs'] = [] 453 | return self._set_up_bp(init_state) 454 | 455 | def _execute_one(self, target, site): 456 | if target.source == target.addr and site.callee != 'EOF': 457 | # Case 1 458 | if 'entry_state' not in self._statistics[target.addr]: 459 | self._statistics[target.addr]['entry_state'] = 0 460 | self._statistics[target.addr]['entry_state'] += 1 461 | init_state = self._create_entry_state(target, site) 462 | self._explore_one(target, site, init_state) 463 | else: 464 | if 'checkpoint_state' not in self._statistics[target.addr]: 465 | self._statistics[target.addr]['checkpoint_state'] = 0 466 | self._statistics[target.addr]['checkpoint_state'] += 1 467 | init_states = self._get_checkpoint_state(target, site) 468 | for x in init_states: 469 | try: 470 | self._explore_one(target, site, x) 471 | except angr.AngrAnalysisError as e: 472 | logger.error(e) 473 | continue 474 | 475 | def run_one(self, target): 476 | for x in tqdm(target.nodes, desc="Exploring nodes in target", leave=False): 477 | try: 478 | self._statistics[target.addr] = {} 479 | self._execute_one(target, target._nodes[x]) 480 | except angr.AngrAnalysisError as e: 481 | logger.error(e) 482 | continue 483 | except (KeyboardInterrupt, AssertionError, AttributeError) as e: 484 | logger.exception(e) 485 | continue 486 | 487 | def run_all(self): 488 | for x in tqdm(self._targets, desc="Exploring targets"): 489 | self.run_one(x) 490 | 491 | self._dump_stats() 492 | 493 | 494 | def _blocks_in_func(self, func, call_sites): 495 | func_blocks = [] 496 | snode = func.get_node(func.addr) 497 | for addr in call_sites: 498 | cur_blocks = [] 499 | tnode = func.get_node(addr) 500 | if tnode is None: 501 | continue 502 | 503 | if nx.has_path(func.graph, snode, tnode) is False: 504 | continue 505 | 506 | cur_blocks = [x.addr for x in func.graph.nodes if 507 | nx.has_path(func.graph, snode, x) and 508 | nx.has_path(func.graph, x, tnode)] 509 | 510 | func_blocks += cur_blocks 511 | 512 | return list(set(func_blocks)) 513 | 514 | def _get_blocks_between(self, src, dst): 515 | funcs = [] 516 | blocks = [] 517 | call_sites = [] 518 | avoid_blocks = [] 519 | callgraph = self.cfg.kb.callgraph 520 | 521 | if nx.has_path(callgraph, src, dst) is False: 522 | logger.error("No path from 0x%x to 0x%x" % (src, dst)) 523 | return None, None 524 | 525 | funcs = [x for x in callgraph.nodes if nx.has_path(callgraph, src, x) 526 | and nx.has_path(callgraph, x, dst)] 527 | 528 | if len(funcs) == 0: 529 | logger.error("No functions found") 530 | return None, None 531 | 532 | for addr in funcs: 533 | if addr == dst: 534 | continue 535 | func = self.cfg.functions.function(addr) 536 | if func is None: 537 | continue 538 | 539 | call_sites = [x for x in func.get_call_sites() 540 | if func.get_call_target(x) in funcs] 541 | 542 | find_blocks = self._blocks_in_func(func, call_sites) 543 | avoid_blocks += func.block_addrs_set - set(find_blocks) 544 | blocks = list(set(blocks+find_blocks)) 545 | 546 | return list(set(blocks)), list(set(avoid_blocks)) 547 | 548 | def _get_call_paths(self, func_addr, level): 549 | if level == 0: 550 | # start from main 551 | main = self.cfg.functions.function(name='main') 552 | if main is None: 553 | if self._project.arch.bits == 64: 554 | try: 555 | f = self.cfg.functions.function(self._project.entry) 556 | assert f is not None 557 | name = self._callee_name(f, self._project.entry) 558 | except angr.AngrCFGError: 559 | logger.error('Could not identify call target') 560 | name = '' 561 | except AssertionError: 562 | logger.error("Could not find _start") 563 | name = '' 564 | if name == '__libc_start_main': 565 | bbl = self.cfg.get_any_node(f.addr) 566 | idx = self.get_target_ins(bbl, 1) 567 | rhs = bbl.block.vex.statements[idx].data 568 | starts = [rhs.constants[0].value] 569 | self.cfg.functions.function(starts[0]).name = 'main' 570 | else: 571 | # Probably a shared object. 572 | logger.error("Couldn't find main.") 573 | logger.error(name) 574 | starts = [self._project.entry] 575 | else: 576 | logger.error("Not implemented yet") 577 | starts = [self._project.entry] 578 | else: 579 | starts = [main.addr] 580 | else: 581 | # Get callers from call stack 582 | starts = [func_addr] 583 | preds = [] 584 | for y in range(level): 585 | for x in starts: 586 | z = list(self.cfg.kb.functions.callgraph.predecessors(x)) 587 | preds = list(set(preds+z)) 588 | if len(preds) == 0: 589 | break 590 | starts = preds 591 | preds = [] 592 | 593 | block_dict = {} 594 | for src in set(starts): 595 | if self._cfg.functions.function(src).name == 'main': 596 | continue 597 | x, y = self._get_blocks_between(src, func_addr) 598 | if x is None: 599 | continue 600 | block_dict[src] = {} 601 | block_dict[src]['find'] = x 602 | block_dict[src]['avoid'] = y 603 | 604 | return block_dict 605 | 606 | def _reach_sink(self, state, report): 607 | args = [] 608 | new_args = [] 609 | sym_vars = [] 610 | second_target = report.state.addr 611 | 612 | if report.site.source is not None: 613 | # Account for saved PC 614 | args = [self._nth_arg(state, report.site.source, saved_pc=True)] 615 | for x in range(report.site.source - 1): 616 | new_args.append(self._nth_arg(state, x+1, saved_pc=True)) 617 | else: 618 | for x in range(10): 619 | args.append(self._nth_arg(state, x+1)) 620 | 621 | for x in args: 622 | sym_arg = claripy.BVS('arg', self.utils.arch.bits) 623 | state.solver.add(sym_arg == x) 624 | sym_vars.append(sym_arg) 625 | new_args.append(sym_arg) 626 | 627 | new_state = self._project.factory.call_state(state.addr, 628 | *new_args, 629 | base_state=state) 630 | new_state.globals['sym_vars'] = state.globals.get('sym_vars', []) 631 | new_state.globals['sym_vars'].extend(sym_vars) 632 | new_state.globals['derefs'] = [] 633 | new_state.globals['no_create'] = True 634 | new_state = self._set_up_bp(new_state) 635 | 636 | sm = self._project.factory.simulation_manager(new_state) 637 | logger.info("Starting exploration to sink @ 0x%x" % report.sink) 638 | sm.explore(find=second_target) 639 | 640 | return sm.found 641 | 642 | def verify_one(self, report, start, block_dict): 643 | avoid = block_dict['avoid'] 644 | first_target = self._cfg.functions.floor_func(report.state.addr) 645 | 646 | if first_target is None: 647 | logger.error("Could not find the function for 0x%x" % report.state.addr) 648 | 649 | assert first_target.addr != start, "Not a caller function" 650 | 651 | self._statistics[first_target.addr][start] = {} 652 | logger.info("Starting verification from 0x%x" % start) 653 | init_state = self._project.factory.blank_state(addr=start) 654 | 655 | if self.cfg.functions.function(start).name == 'main': 656 | # ARG_MAX 657 | if self.utils.arch.bits == 64: 658 | init_state.solver.add(init_state.regs.rdi < 0x200000) 659 | 660 | final_states = [] 661 | sat_states = [] 662 | 663 | pg = self._project.factory.simulation_manager(init_state) 664 | self._watchdog_event = threading.Event() 665 | self._watchdog_event.clear() 666 | t = threading.Thread(target=self._watchdog, args=(600,)) 667 | t.start() 668 | # signal.alarm(600) 669 | try: 670 | logger.info("Starting exploration to 0x%x" % first_target.addr) 671 | start_time = time.time() 672 | pg.explore(find=first_target.addr, avoid=avoid) 673 | 674 | self._statistics[first_target.addr][start]['paths_from_callers'] = len(pg.found) 675 | assert len(pg.found) > 0, "No paths found" 676 | 677 | end = time.time() 678 | logger.debug("Found %d paths" % len(pg.found)) 679 | self._statistics[first_target.addr][start]['exploring_callers'] = int(end - start_time) 680 | self._watchdog_event.set() 681 | t.join() 682 | 683 | self._watchdog_event.clear() 684 | t = threading.Thread(target=self._watchdog, args=(600,)) 685 | t.start() 686 | start_time = time.time() 687 | for pp in pg.found: 688 | final_states += self._reach_sink(pp, report) 689 | 690 | self._statistics[first_target.addr][start]['paths_to_sink'] = len(final_states) 691 | assert len(final_states) > 0, "No paths found" 692 | 693 | end = time.time() 694 | self._statistics[first_target.addr][start]['reaching_sink'] = int(end - start_time) 695 | logger.debug("Found %d states" % len(final_states)) 696 | 697 | self._watchdog_event.set() 698 | t.join() 699 | for state in final_states: 700 | if self._check_state(state, report.site, None, self._statistics[first_target.addr][start]) is True: 701 | sat_states.append(state) 702 | except (TimeoutException, KeyboardInterrupt, AssertionError) as e: 703 | self._watchdog_event.set() 704 | self._timeout_received = True 705 | t.join() 706 | logger.debug("Got an exception") 707 | logger.exception(e) 708 | 709 | if len(sat_states) == 0: 710 | return None 711 | 712 | # output = {'function': first_target.addr, 'bbl': report.site.bbl, 713 | # 'bbl_history': list(sat_states[0].history.bbl_addrs), 714 | # 'callstack': [x.current_function_address for x in sat_states[0].callstack] 715 | # } 716 | output = ArbiterReport(bbl=report.site.bbl, function=first_target.addr, 717 | bbl_history=list(sat_states[0].history.bbl_addrs), 718 | function_history=[x.current_function_address for x in sat_states[0].callstack]) 719 | if report.site.callee == 'EOF': 720 | # output['bbl'] = self._first_bbl(report.state) 721 | output.bbl = self._first_bbl(report.state) 722 | return output 723 | 724 | def convert_reports(self): 725 | TP = [] 726 | for sink in self.reports: 727 | report = self.reports[sink] 728 | try: 729 | func_addr = self._cfg.functions.floor_func(report.state.addr).addr 730 | except AttributeError: 731 | func_addr = 0 732 | bbl_history = list(report.state.history.bbl_addrs) 733 | TP.append(ArbiterReport(sink, func_addr, bbl_history, [func_addr])) 734 | 735 | return TP 736 | 737 | def verify(self, report, blocks): 738 | output = None 739 | for x in blocks: 740 | try: 741 | output = self.verify_one(report, x, blocks[x]) 742 | if output is not None: 743 | break 744 | except AssertionError as e: 745 | self._timeout_received = True 746 | logger.error(e) 747 | continue 748 | 749 | return output 750 | 751 | def postprocessing(self, pred_level=1): 752 | ''' 753 | Return a list of ArbiterReport's 754 | ''' 755 | if pred_level == -1: 756 | return self.convert_reports() 757 | 758 | logger.info("Starting postprocessing") 759 | self._stats_filename = 'FP.json' 760 | TP = [] 761 | 762 | self._statistics = {} 763 | self._statistics['satisfied_states'] = len(self.reports) 764 | if len(self.reports) == 0: 765 | logger.error("No targets for postprocessing") 766 | return 767 | 768 | signal.alarm(0) 769 | symbols = ['strlen', 'strchr'] 770 | for x in symbols: 771 | if self._project.is_symbol_hooked(x): 772 | self._project.unhook_symbol(x) 773 | self._project.hook_symbol(x, angr.SIM_PROCEDURES['libc'][x]()) 774 | 775 | symbols = ['strdup', 'getenv'] 776 | obj = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained']() 777 | for x in symbols: 778 | if self._project.is_symbol_hooked(x): 779 | self._project.hook_symbol(x, obj) 780 | 781 | func_sink_map = {} 782 | for sink in self.reports: 783 | report = self.reports[sink] 784 | try: 785 | func_addr = self._cfg.functions.floor_func(report.state.addr).addr 786 | except AttributeError: 787 | if self._cfg.functions.floor_func(report.state.addr) is None: 788 | logger.error("Could not find function 0x%x" % report.state.addr) 789 | continue 790 | if func_addr not in func_sink_map: 791 | func_sink_map[func_addr] = [] 792 | func_sink_map[func_addr].append(report) 793 | 794 | for func_addr in func_sink_map: 795 | self._statistics[func_addr] = {} 796 | logger.info("Finding callers for function @ %#x" % func_addr) 797 | blocks = self._get_call_paths(func_addr, pred_level) 798 | if len(blocks) == 0: 799 | logger.error("No paths to function @ 0x%x" % func_addr) 800 | continue 801 | 802 | if len(blocks) == 1 and func_addr in blocks.keys(): 803 | logger.error("No callers found for func @ 0x%x" % func_addr) 804 | continue 805 | 806 | self._statistics[func_addr]['callers'] = len(blocks) 807 | for report in func_sink_map[func_addr]: 808 | is_tp = self.verify(report, blocks) 809 | if is_tp is not None: 810 | TP.append(is_tp) 811 | logger.info("Done with function @ %#x" % func_addr) 812 | 813 | logger.info("Finished postprocessing") 814 | 815 | self._dump_stats() 816 | 817 | return TP 818 | 819 | 820 | 821 | class TimeoutException(Exception): 822 | def __init__(self, message, errors): 823 | super(TimeoutException, self).__init__(message) 824 | self.errors = errors 825 | -------------------------------------------------------------------------------- /arbiter/target.py: -------------------------------------------------------------------------------- 1 | import angr 2 | import claripy 3 | from claripy.errors import ClaripyOperationError 4 | 5 | class Sink(): 6 | def __init__(self, bbl=0, size=0, callee='', arglist=[]): 7 | self._target = {'bbl': bbl, 8 | 'size': size, 9 | 'callee': callee, 10 | 'source': None, 11 | 'args': arglist} 12 | self._flag = False 13 | 14 | def __str__(self): 15 | return f"Sink(BBL={hex(self.bbl)}, Callee={self.callee}, args={self.args}" 16 | 17 | @property 18 | def fmt(self): 19 | return self._target['args'].index('fmt') + 1 20 | 21 | @property 22 | def src(self): 23 | return self._target['args'].index('i') + 1 24 | 25 | @property 26 | def sz(self): 27 | if self.callee == "EOF": 28 | return 0 29 | return self._target['args'].index('n') + 1 30 | 31 | @property 32 | def bbl(self): 33 | return self._target['bbl'] 34 | 35 | @bbl.setter 36 | def bbl(self, addr): 37 | assert addr in self._func.block_addrs_set 38 | self._target['bbl'] = addr 39 | 40 | @property 41 | def size(self): 42 | return self._target['size'] 43 | 44 | @size.setter 45 | def size(self, val): 46 | assert val >= 0 47 | self._target['size'] = val 48 | 49 | @property 50 | def callee(self): 51 | return self._target['callee'] 52 | 53 | @callee.setter 54 | def callee(self, val): 55 | assert len(val) > 0 56 | self._target['callee'] = val 57 | 58 | @property 59 | def source(self): 60 | # if self._target['source'] is None: 61 | # return -1 62 | return self._target['source'] 63 | 64 | @source.setter 65 | def source(self, val): 66 | if val <= 0: 67 | val = None 68 | else: 69 | val = int(val) 70 | self._target['source'] = val 71 | 72 | @property 73 | def flag(self): 74 | return self._flag 75 | 76 | @flag.setter 77 | def flag(self, val): 78 | self._flag = val 79 | 80 | @property 81 | def args(self): 82 | return self._target['args'] 83 | 84 | @args.setter 85 | def args(self, arg_list): 86 | self._target['args'] = arg_list 87 | 88 | 89 | class SA1_Target(): 90 | def __init__(self, func): 91 | self._func = func 92 | self._nodes = {} 93 | 94 | def __str__(self): 95 | return f"SA1_Target(func={hex(self.addr)}, nodes={self.node_count})" 96 | 97 | def add_node(self, site, size, cfg, arglist): 98 | if 'r' in arglist: 99 | self._nodes[site] = Sink(site, size, "EOF", arglist) 100 | return 101 | 102 | callee = self._func.get_call_target(site) 103 | assert callee is not None 104 | 105 | target = cfg.functions.function(callee) 106 | assert target is not None 107 | 108 | self._nodes[site] = Sink(site, size, target.demangled_name, arglist) 109 | 110 | @property 111 | def addr(self): 112 | return self._func.addr 113 | 114 | @property 115 | def func(self): 116 | return self._func 117 | 118 | @property 119 | def nodes(self): 120 | return sorted(self._nodes.keys()) 121 | 122 | @property 123 | def node_count(self): 124 | return len(self._nodes) 125 | 126 | 127 | class SA2_Target(): 128 | ''' 129 | A class to represent a target function 130 | Must contain a CFGAccurate object, a DDG and CDG object and a Function 131 | object. 132 | And then a dictionary which contain details of the bbl and the 133 | sink 134 | ''' 135 | def __init__(self, cfg, cdg, ddg, func): 136 | ''' 137 | :param cfg : The CFGEmulated object 138 | :param ddg : The DDG object 139 | :param cdg : The CDG object 140 | :param func : The Function object 141 | ''' 142 | self._cfg = cfg 143 | self._ddg = ddg 144 | self._cdg = cdg 145 | self._func = func 146 | self._bs = None 147 | self._nodes = {} 148 | self._source = None 149 | 150 | def __str__(self): 151 | return f"SA2_Target(func={hex(self.addr)}, source={self.source}, nodes={self.node_count})" 152 | 153 | def str_ref(self, str_addr): 154 | for addr, val in self._func.string_references(vex_only=True): 155 | if addr == str_addr: 156 | return val 157 | 158 | def get_any_ddg_node(self, addr, idx): 159 | dnode = None 160 | for node in self._ddg.data_graph.nodes: 161 | if node.location.block_addr == addr: 162 | if node.location.stmt_idx == idx: 163 | dnode = node 164 | return dnode 165 | 166 | def stmt_from_ddg_node(self, dnode): 167 | b = self._cfg.get_any_node(dnode.location.block_addr).block 168 | return b.vex.statements[dnode.location.stmt_idx] 169 | 170 | def block_idx(self, bbl): 171 | return sorted(list(self.func.block_addrs_set)).index(bbl) 172 | 173 | def prev_block(self, bbl): 174 | idx = self.block_idx(bbl) 175 | return sorted(list(self.func.block_addrs_set))[idx - 1] 176 | 177 | def next_block(self, bbl): 178 | idx = self.block_idx(bbl) 179 | if len(self.func.block_addrs_set) <= idx: 180 | return None 181 | return sorted(list(self.func.block_addrs_set))[idx + 1] 182 | 183 | def expr_from_state(self, project, state, arg_num): 184 | # TODO This is broken 185 | return None 186 | cca = project.analyses.CallingConvention(self._func) 187 | args = cca.cc.arg_locs(cca.prototype) 188 | if cca.cc is None or args is None: 189 | return None 190 | if arg_num == 0: 191 | return cca.cc.return_val() 192 | elif len(args) >= arg_num: 193 | return cca.cc.arg(state, arg_num - 1) 194 | 195 | def checkpoint_is_ret(self, name): 196 | return self.source[name] == 0 197 | 198 | @property 199 | def cfg(self): 200 | return self._cfg 201 | 202 | @property 203 | def cdg(self): 204 | return self._cdg 205 | 206 | @property 207 | def ddg(self): 208 | return self._ddg 209 | 210 | @property 211 | def node_count(self): 212 | return len(self._nodes) 213 | 214 | @property 215 | def flag(self): 216 | return len(self._nodes) > 0 217 | 218 | @property 219 | def addr(self): 220 | return self._func.addr 221 | 222 | @property 223 | def name(self): 224 | return self._func.name 225 | 226 | @property 227 | def func(self): 228 | return self._func 229 | 230 | @property 231 | def nodes(self): 232 | return sorted(self._nodes.keys()) 233 | 234 | @property 235 | def source(self): 236 | return self._source 237 | 238 | @source.setter 239 | def source(self, checkpoint): 240 | self._source = checkpoint 241 | 242 | def remove(self, site): 243 | del self._nodes[site] 244 | 245 | def sink_name(self, site): 246 | return self._nodes[site].callee 247 | 248 | 249 | class Report: 250 | def __init__(self, state, site): 251 | self._state = state 252 | self._site = site 253 | 254 | def __str__(self): 255 | return f"Report(state={self.state}, site={hex(self.sink)})" 256 | 257 | @property 258 | def state(self): 259 | return self._state 260 | 261 | @property 262 | def sink(self): 263 | return self._site.bbl 264 | 265 | @property 266 | def site(self): 267 | return self._site 268 | 269 | 270 | class ArbiterReport: 271 | def __init__(self, bbl, function, bbl_history, function_history): 272 | """ 273 | All arguments are integers/list of integers 274 | """ 275 | self._bbl = bbl 276 | self._function = function 277 | self._bbl_history = bbl_history 278 | self._function_history = function_history 279 | 280 | 281 | def __str__(self): 282 | return f"ArbiterRepor(bbl={hex(self.bbl)}, function={hex(self.function)})" 283 | 284 | @property 285 | def bbl(self): 286 | return self._bbl 287 | 288 | @bbl.setter 289 | def bbl(self, val): 290 | self._bbl = val 291 | 292 | @property 293 | def function(self): 294 | return self._function 295 | 296 | @property 297 | def bbl_history(self): 298 | return self._bbl_history 299 | 300 | @property 301 | def function_history(self): 302 | return self._function_history 303 | 304 | 305 | class DerefHook(): 306 | def _find_in_list(self, child, sym_vars): 307 | for x in sym_vars: 308 | if child.length != x.length: 309 | continue 310 | elif not isinstance(child, type(x)): 311 | continue 312 | result = child == x 313 | if result.is_true(): 314 | return True 315 | 316 | return False 317 | 318 | def _find_child_in_list(self, ast, vars): 319 | try: 320 | for child in list(set(ast.recursive_leaf_asts)): 321 | if self._find_in_list(child, vars): 322 | return True 323 | except ClaripyOperationError: 324 | # Could not iterate over leaf ast's 325 | #TODO how to handle this ? 326 | return False 327 | 328 | if self._find_in_list(ast, vars): 329 | return True 330 | 331 | return False 332 | 333 | def _get_child_from_list(self, ast, sym_vars): 334 | for child in list(set(ast.recursive_leaf_asts)): 335 | if self._find_in_list(child, sym_vars): 336 | return child 337 | 338 | if self._find_in_list(ast, sym_vars): 339 | return ast 340 | 341 | def _find_bit_in_ast(self, bit, ast): 342 | for idx in range(0, ast.length): 343 | result = ast[idx] == bit 344 | if result.is_true(): 345 | return idx 346 | 347 | return None 348 | 349 | def _mem_write_hook(self, state): 350 | if state.globals.get('track_write', False) is False: 351 | return 352 | 353 | expr = state.inspect.mem_write_address 354 | 355 | if type(expr) == int: 356 | return 357 | 358 | if self._find_child_in_list(expr, state.globals['sym_vars']) is False: 359 | return 360 | 361 | orig_expr = self._get_child_from_list(expr, state.globals['sym_vars']) 362 | 363 | if self._find_in_list(orig_expr, state.globals['derefs']) is True: 364 | return 365 | 366 | state.solver.add(orig_expr == 0) 367 | state.globals['derefs'].append(orig_expr) 368 | 369 | 370 | def _mem_read_hook(self, state): 371 | expr = state.inspect.mem_read_address 372 | val = state.inspect.mem_read_expr 373 | 374 | # Don't need to worry if this address is 375 | # 1) An address in the BSS 376 | # 2) Not dependent on the arguments 377 | # 3) Already dereferenced before 378 | if type(expr) == int: 379 | return 380 | 381 | if self._find_child_in_list(expr, state.globals['sym_vars']) is False: 382 | return 383 | 384 | flag1 = self._find_in_list(expr, state.globals['derefs']) 385 | flag2 = self._find_child_in_list(val, state.globals['sym_vars']) 386 | 387 | if flag1 and flag2: 388 | return 389 | 390 | if state.globals.get('no_create', False) is True: 391 | state.globals['sym_vars'].append(val) 392 | state.globals['derefs'].append(expr) 393 | return 394 | 395 | sym_var = claripy.BVS('df_var', state.inspect.mem_read_length*8) 396 | state.globals['derefs'].append(expr) 397 | state.globals['sym_vars'].append(sym_var) 398 | state.memory.store(expr, sym_var, endness=angr.archinfo.Endness.LE) 399 | state.inspect.mem_read_expr = sym_var 400 | 401 | 402 | 403 | class DefaultHook(angr.SimProcedure, DerefHook): 404 | def _push_regs(self, state): 405 | state.stack_push(state.regs.r9) 406 | state.stack_push(state.regs.r8) 407 | state.stack_push(state.regs.rcx) 408 | state.stack_push(state.regs.rdx) 409 | state.stack_push(state.regs.rsi) 410 | state.stack_push(state.regs.rdi) 411 | 412 | def _nth_arg(self, state, n): 413 | state_copy = state.copy() 414 | if state.arch.bits == 64: 415 | self._push_regs(state_copy) 416 | 417 | for _ in range(n - 1): 418 | state_copy.stack_pop() 419 | 420 | return state_copy.stack_pop() 421 | 422 | def run(self): 423 | expr = claripy.BVS('sim_retval', self.state.project.arch.bits) 424 | self.state.solver.add(expr != 0) 425 | self.state.globals['sym_vars'].append(expr) 426 | return expr 427 | 428 | class FirstArgHook(angr.SimProcedure): 429 | def run(self, arg): 430 | expr = claripy.BVS('sim_retval', self.state.project.arch.bits) 431 | self.state.solver.add(expr == arg) 432 | self.state.globals['sym_vars'].append(expr) 433 | return arg 434 | 435 | class CheckpointHook(DefaultHook): 436 | def run(self, **kwargs): 437 | assert 'arg_num' in kwargs['kwargs'] 438 | arg_num = kwargs['kwargs']['arg_num'] 439 | if self.state.globals.get('globals', None) is None: 440 | self.state.globals['sym_vars'] = [] 441 | if arg_num == 0: 442 | sym_var = claripy.BVS('ret', self.state.arch.bits) 443 | self.state.globals['sym_vars'].append(sym_var) 444 | return sym_var 445 | 446 | expr = self._nth_arg(self.state, arg_num) 447 | self.state.globals['sym_vars'].append(expr) 448 | 449 | 450 | 451 | class StrlenHook(DefaultHook): 452 | def run(self): 453 | if self.state.project.arch.bits == 32: 454 | inp = self.state.stack_pop() 455 | elif self.state.project.arch.bits == 64: 456 | inp = self.state.regs.rdi 457 | sym_vars = self.state.globals['sym_vars'] 458 | expr = claripy.BVS('len_retval', self.state.project.arch.bits) 459 | self.state.solver.add(expr < 2 ** int(self.state.project.arch.bits/2)) 460 | 461 | if self._find_child_in_list(inp, sym_vars) is False: 462 | return expr 463 | 464 | self.state.solver.add(expr != 0) 465 | self.state.globals['sym_vars'].append(expr) 466 | return expr 467 | 468 | 469 | class StrchrHook(DefaultHook): 470 | def run(self): 471 | if self.state.project.arch.bits == 32: 472 | inp = self.state.stack_pop() 473 | elif self.state.project.arch.bits == 64: 474 | inp = self.state.regs.rdi 475 | sym_vars = self.state.globals['sym_vars'] 476 | expr = claripy.BVS('chr_retval', self.state.project.arch.bits) 477 | 478 | if self._find_child_in_list(inp, sym_vars) is False: 479 | return expr 480 | 481 | self.state.solver.add(expr != 0) 482 | self.state.solver.add(expr < 2 ** int(self.state.project.arch.bits/2)) 483 | retval = expr + inp 484 | self.state.globals['sym_vars'].append(expr) 485 | return retval 486 | 487 | 488 | class GetenvHook(DefaultHook): 489 | def run(self): 490 | expr = claripy.BVS('env_retval', self.state.project.arch.bits) 491 | self.state.globals['sym_vars'].append(expr) 492 | return expr 493 | -------------------------------------------------------------------------------- /arbiter/utils.py: -------------------------------------------------------------------------------- 1 | import angr 2 | from capstone.x86 import * 3 | from angr import archinfo 4 | from archinfo.arch_x86 import ArchX86 5 | from archinfo.arch_amd64 import ArchAMD64 6 | 7 | 8 | class Utils: 9 | def __init__(self, project): 10 | self.project = project 11 | self.arch = self.project.arch 12 | 13 | # This should constantly be updated to accomodate all libc functions 14 | self.func_map = {'strcpy': ['o', 'i'], 15 | 'stpcpy': ['o', 'i'], 16 | 'strncpy': ['o', 'i', 'n'], 17 | 'sprintf': ['o', 'fmt'], 18 | 'sprintf_chk': ['o', 'c', 'n', 'fmt'], 19 | 'memcpy': ['o', 'i', 'n'], 20 | 'malloc': ['n'], 21 | 'realloc': ['p', 'n'], 22 | 'calloc': ['n', 'n'], 23 | 'ret': ['r']} 24 | self.misc_map = {'strlen': ['i'], 25 | 'strdup': ['i'], 26 | 'strndup': ['i', 'n']} 27 | 28 | def dst(self, func_name): 29 | ''' 30 | The argument of the func_name which contains the destination 31 | ''' 32 | return self.func_map[func_name].index('o') + 1 33 | 34 | def src(self, func_name): 35 | ''' 36 | The argument of the func_name which contains the source 37 | ''' 38 | return self.func_map[func_name].index('i') + 1 39 | 40 | def fmt(self, func_name): 41 | ''' 42 | The argument of the func_name which contains the format string 43 | ''' 44 | return self.func_map[func_name].index('fmt') + 1 45 | 46 | def sz(self, func_name): 47 | return self.func_map[func_name].index('n') + 1 48 | 49 | def misc_src(self, func_name): 50 | if 'n' in self.misc_map[func_name]: 51 | return self.misc_map[func_name].index('n') + 1 52 | else: 53 | return self.misc_map[func_name].index('i') + 1 54 | 55 | @property 56 | def ret_reg(self): 57 | return self.arch.ret_offset 58 | 59 | def arg_to_offset(self, arg_num): 60 | for key in self.arch.argument_register_positions: 61 | if self.arch.argument_register_positions[key] + 1 == arg_num: 62 | return key 63 | 64 | def arg_to_reg(self, arg_num, sz=8): 65 | return self.vex_to_name(self.arg_to_offset(arg_num), sz) 66 | 67 | def reg_to_arg(self, regnum): 68 | if regnum == self.ret_reg: 69 | return 0 70 | return self.arch.argument_register_positions[regnum] + 1 71 | 72 | def arg_index(self, reg): 73 | ''' 74 | Returns the argument number corresponding to reg 75 | ''' 76 | return self.arch.argument_register_positions[reg] + 1 77 | 78 | def op_is_reg(self, op): 79 | ''' 80 | Check whether the operand type is register or not 81 | ''' 82 | if op.type == X86_OP_REG: 83 | return True 84 | 85 | return False 86 | 87 | def name_to_vex(self, reg_name): 88 | ''' 89 | Return the VEX representation of the register reg_name 90 | Note: This is different from the capstone representation of registers 91 | ''' 92 | return self.arch.registers[reg_name][0] 93 | 94 | def vex_to_name(self, reg, sz): 95 | ''' 96 | Return the name of the register from the VEX representation 97 | ''' 98 | return self.arch.register_size_names[(reg, sz)] 99 | 100 | def reg_from_ddg_node(self, ddg_node, bits): 101 | ''' 102 | Return the name of the register in the ddg_node 103 | ''' 104 | assert type(ddg_node.variable) == angr.sim_variable.SimRegisterVariable 105 | 106 | return ddg_node.variable.reg 107 | 108 | def is_add32(self, stmt): 109 | return stmt.tag == 'Iex_Binop' and stmt.op == 'Iop_Add32' 110 | 111 | def is_add(self, stmt): 112 | return stmt.op == 'Iop_Add32' or stmt.op == 'Iop_Add64' 113 | 114 | def is_sub(self, stmt): 115 | return stmt.op == 'Iop_Sub32' or stmt.op == 'Iop_Sub64' 116 | 117 | def is_mul(self, stmt): 118 | return stmt.op == 'Iop_Mul32' or stmt.op == 'Iop_Mul64' 119 | 120 | def is_div(self, stmt): 121 | return stmt.op == 'Iop_Div32' or stmt.op == 'Iop_Div64' 122 | 123 | def is_imark(self, stmt): 124 | return stmt.tag == 'Ist_IMark' 125 | 126 | def is_ite(self, stmt): 127 | return stmt.tag == 'Iex_ITE' 128 | 129 | def is_const(self, stmt): 130 | return stmt.tag == 'Iex_Const' 131 | 132 | def is_reg_write(self, stmt): 133 | return stmt.tag == 'Ist_Put' 134 | 135 | def is_reg_read(self, stmt): 136 | return stmt.tag == 'Iex_Get' 137 | 138 | def is_tmp_write(self, stmt): 139 | return stmt.tag == 'Ist_WrTmp' 140 | 141 | def is_tmp_read(self, stmt): 142 | return stmt.tag == 'Iex_RdTmp' 143 | 144 | def is_tmp_unop(self, stmt): 145 | return stmt.tag == 'Iex_Unop' 146 | 147 | def is_tmp_binop(self, stmt): 148 | return stmt.tag == 'Iex_Binop' 149 | 150 | def is_arith(self, stmt): 151 | return self.is_tmp_unop(stmt) or self.is_tmp_binop(stmt) 152 | 153 | def is_tmp_load(self, stmt): 154 | return stmt.tag == 'Iex_Load' 155 | 156 | def is_tmp_store(self, stmt): 157 | return stmt.tag == 'Ist_Store' 158 | 159 | def target_reg(self, stmt): 160 | return stmt.offset 161 | 162 | def target_tmp(self, stmt): 163 | return stmt.tmp 164 | 165 | def target_const(self, stmt): 166 | return stmt.con.value 167 | 168 | def is_stack_var(self, variable): 169 | return type(variable) == angr.sim_variable.SimStackVariable 170 | 171 | def store_in_stack(self, ins): 172 | ''' 173 | Check if ins corresponds to `mov dword[esp+x], {r/imm}` 174 | ''' 175 | if ins.insn.mnemonic != 'mov': 176 | return False 177 | 178 | if len(ins.insn.operands) < 1: 179 | return False 180 | 181 | first = ins.insn.operands[0] 182 | if first.mem.base == X86_REG_ESP or first.mem.base == X86_REG_RSP: 183 | return True 184 | 185 | return False 186 | 187 | def disp(self, ins): 188 | return ins.insn.disp 189 | 190 | 191 | class FatalError(Exception): 192 | def __init__(self, message): 193 | self.message = message 194 | 195 | class DataDependencyError(Exception): 196 | def __init__(self, message): 197 | self.message = message 198 | 199 | class ConstantDataError(Exception): 200 | def __init__(self, message): 201 | self.message = message 202 | -------------------------------------------------------------------------------- /dataset/binary_stats.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/dataset/binary_stats.zip -------------------------------------------------------------------------------- /dataset/juliet_testcases.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/dataset/juliet_testcases.zip -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | This directory contains examples of using Arbiter to detect previously known vulnerabilities. 2 | 3 | The vulnerable binaries are present inside `cve-binaries` directory and the corresponding templates used to detect the bugs can be found inside `cve-vuln_templates`. 4 | 5 | The `cve-logs` directory contains the output generated by Arbiter when running the VD against the target binary. 6 | 7 | Please refer to the README file inside `cve-logs` for an explanation on how to interpret the output. 8 | 9 | 10 | # Running the examples 11 | Use the `run_arbiter` script using the `-f` flag to specify a VD inside `cve-vuln_templates` and the `-t` flag to specify a binary inside `cve-binaries`. 12 | 13 | Optionally, set the `-l` and `-j` flags to a directory in order to view the output from Arbiter. 14 | 15 | For example, in order to run the CVE-XXXX-YYYY example, the command used would look like 16 | 17 | ``` 18 | cd 19 | mkdir 20 | mkdir 21 | ./vuln_templates/run_arbiter.py -f examples/cve-vuln_templates/vd_cve-xxxx-yyyy.py -t examples/cve-binaries/cve-xxxx-yyyy -l -j 22 | ``` -------------------------------------------------------------------------------- /examples/cve-binaries/cve-2018-10388: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/examples/cve-binaries/cve-2018-10388 -------------------------------------------------------------------------------- /examples/cve-binaries/cve-2022-26495: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/examples/cve-binaries/cve-2022-26495 -------------------------------------------------------------------------------- /examples/cve-binaries/cve-XXXX-YYYY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/examples/cve-binaries/cve-XXXX-YYYY -------------------------------------------------------------------------------- /examples/cve-logs/README.md: -------------------------------------------------------------------------------- 1 | This file explains the structure of the output files generated by Arbiter 2 | 3 | # The .log file 4 | 5 | 6 | Enable this logging using the `-l` parameter to the `run_arbiter` script 7 | 8 | 9 | This file contains all the logs generated by Arbiter in the format "(date)s - (name)s - (LEVEL) - (msg)" 10 | 11 | 12 | The static data-dependency analysis of Arbiter considers constants as negatives and terminates the analysis when a constant value is encountered. 13 | 14 | 15 | The symbolic execution phase of Arbiter can generate two types of states depending on whether a source function is explicitly provided. 16 | 17 | 18 | 1. Entry state : This situation is used when the data-dependency starts from the function entry point. (ie no source function provided) 19 | 2. Checkpoint state : This situation is used when the data-dependency starts from a provided source function. 20 | 21 | 22 | # Recon.json 23 | 24 | 25 | This file contains output from the recon step of Arbiter. 26 | It contains one dictionary with different key-value pairs that will be explained below. 27 | 28 | ``` 29 | { 30 | "cfg_creation": 1, 31 | "cfg_blocks": 2932, 32 | "cfg_edges": 5723, 33 | "recovered_functions": 658, 34 | "identified_functions": 3 35 | } 36 | 37 | ``` 38 | 39 | The `cfg_creation` value denotes the amount of time (in seconds) spent on recovering the CFG of the binary. 40 | 41 | The `cfg_blocks`, `cfg_edges` and `recovered_functions` represent the number of blocks, edges and functions recovered from the binary. 42 | 43 | The `identified_functions` denotes the number of functions that have been identified to contain the sink of interest. 44 | 45 | 46 | # DDA.json 47 | 48 | 49 | This file contains the output from the static data-dependency analysis of Arbiter. 50 | It contains one dictionary with multiple nested dictionaries. 51 | 52 | ``` 53 | { 54 | "identified_functions": 3, 55 | "4205545": { 56 | "sink_count": 1, 57 | "cfg_creation": 5, 58 | "ddg_creation": 7, 59 | "cdg_creation": 0, 60 | "sources": 27, 61 | "constants": 1 62 | }, 63 | ... 64 | } 65 | ``` 66 | 67 | In the outermost dictionary, the `identified_functions` denotes the number of functions that were passed as input to this step of Arbiter. 68 | This value is equal to the `identified_functions` value from the Recon.json file. 69 | 70 | 71 | Each nested dictionary in this file corresponds to a function identified in the recon step. 72 | The address of the function is used as the key to this nested dictionary. 73 | 74 | In the nested dictionaries, the `sink_count` represents the number of sinks identified in the function. 75 | 76 | The values `cfg_creation`, `ddg_creation` and `cdg_creation` represent the time spent (in seconds) in creating the CFG, DDG and CDG respectively. 77 | 78 | The `sources` key represents the number of calls to source-functions identified in this function. 79 | 80 | The `constants` value represents the number of data-dependencies that resulted in constant values. 81 | 82 | If `sink_count - constants` is greater than 0, this function will be marked for the next step of Arbiter's analysis. 83 | 84 | 85 | # UCSE.json 86 | 87 | 88 | This file contains the output from the under-constrained symbolic execution analysis of Arbiter. 89 | It contains one dictionary with multiple nested dictionaries similar to the previous DDA.json file. 90 | 91 | ``` 92 | { 93 | "identified_functions": 2, 94 | "4242068": { 95 | "entry_state": 1, 96 | "paths_found": 1, 97 | "paths_timedout": 0, 98 | "exploration_time": 0, 99 | "expressions_tracked": 1, 100 | "filtered_expressions": 1, 101 | "sat_states": 1 102 | }, 103 | "4242537": { 104 | "checkpoint_state": 1, 105 | "paths_found": 1, 106 | "paths_timedout": 0, 107 | "expressions_tracked": 1, 108 | "filtered_expressions": 1, 109 | "sat_states": 1, 110 | "exploration_time": 0 111 | } 112 | ... 113 | } 114 | 115 | ``` 116 | 117 | In the outermost dictionary, the `identified_functions` denotes the number of functions that were passed as input to this step of Arbiter. 118 | 119 | 120 | Each nested dictionary in this file corresponds to a function identified in the static data-dependency analysis step. 121 | The address of the function is used as the key to this nested dictionary. 122 | 123 | In the nested dictionaries, the `paths_found` and `paths_timedout` represent the number of paths that successfully reached the target sink and those that timed out before reaching the sink respectively. 124 | 125 | 126 | The nested dictionary contains either the `entry_state` or `checkpoint_state` key depending upon whether a source-function was identified in the current function. 127 | The value of this key represents the number of initial symbolic states generated. 128 | 129 | The `expressions_tracked` denotes the number of symbolic expressions tracked during the UCSE step. 130 | 131 | Since the initial symbolic expression might be used to generate multiple expressions, Arbiter filters out the tracked expressions that do not influence the final value passed to the sink. 132 | The `filtered_expressions` denote the number of expressions that remain after this filtering step. 133 | 134 | The `exploration_time` represents the time (in seconds) that was spent during UCSE. 135 | 136 | And finally the `sat_states` represents the number of satisfied states. 137 | 138 | If the value `sat_states` is greater than 0, it means that Arbiter has found a bug in this function. 139 | -------------------------------------------------------------------------------- /examples/cve-logs/cve-2018-10388/DDA.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 3, 3 | "4205545": { 4 | "sink_count": 1, 5 | "cfg_creation": 5, 6 | "ddg_creation": 7, 7 | "cdg_creation": 0, 8 | "sources": 27, 9 | "constants": 1 10 | }, 11 | "4242068": { 12 | "sink_count": 1, 13 | "cfg_creation": 0, 14 | "ddg_creation": 0, 15 | "cdg_creation": 0, 16 | "sources": 0, 17 | "constants": 0 18 | }, 19 | "4242537": { 20 | "sink_count": 1, 21 | "cfg_creation": 0, 22 | "ddg_creation": 0, 23 | "cdg_creation": 0, 24 | "sources": 3, 25 | "constants": 0 26 | } 27 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-2018-10388/Recon.json: -------------------------------------------------------------------------------- 1 | { 2 | "cfg_creation": 1, 3 | "cfg_blocks": 2932, 4 | "cfg_edges": 5723, 5 | "recovered_functions": 658, 6 | "identified_functions": 3 7 | } 8 | -------------------------------------------------------------------------------- /examples/cve-logs/cve-2018-10388/UCSE.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 2, 3 | "4242068": { 4 | "entry_state": 1, 5 | "paths_found": 1, 6 | "paths_timedout": 0, 7 | "exploration_time": 0, 8 | "expressions_tracked": 1, 9 | "filtered_expressions": 1, 10 | "sat_states": 1 11 | }, 12 | "4242537": { 13 | "checkpoint_state": 1, 14 | "paths_found": 1, 15 | "paths_timedout": 0, 16 | "expressions_tracked": 1, 17 | "filtered_expressions": 1, 18 | "sat_states": 1, 19 | "exploration_time": 0 20 | } 21 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-2022-26495/DDA.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 10, 3 | "4209810": { 4 | "sink_count": 1, 5 | "cfg_creation": 0, 6 | "ddg_creation": 0, 7 | "cdg_creation": 0, 8 | "sources": 0, 9 | "constants": 1 10 | }, 11 | "4224625": { 12 | "sink_count": 1, 13 | "cfg_creation": 0, 14 | "ddg_creation": 0, 15 | "cdg_creation": 0, 16 | "sources": 0, 17 | "constants": 1 18 | }, 19 | "4228751": { 20 | "sink_count": 1, 21 | "cfg_creation": 0, 22 | "ddg_creation": 0, 23 | "cdg_creation": 0, 24 | "sources": 0, 25 | "constants": 0 26 | }, 27 | "4229729": { 28 | "sink_count": 1, 29 | "cfg_creation": 0, 30 | "ddg_creation": 0, 31 | "cdg_creation": 0, 32 | "sources": 2, 33 | "constants": 0 34 | }, 35 | "4231002": { 36 | "sink_count": 1, 37 | "cfg_creation": 0, 38 | "ddg_creation": 0, 39 | "cdg_creation": 0, 40 | "sources": 1, 41 | "constants": 1 42 | }, 43 | "4232332": { 44 | "sink_count": 2, 45 | "cfg_creation": 0, 46 | "ddg_creation": 0, 47 | "cdg_creation": 0, 48 | "sources": 0, 49 | "constants": 0 50 | }, 51 | "4232982": { 52 | "sink_count": 1, 53 | "cfg_creation": 0, 54 | "ddg_creation": 0, 55 | "cdg_creation": 0, 56 | "sources": 0, 57 | "constants": 0 58 | }, 59 | "4235645": { 60 | "sink_count": 1, 61 | "cfg_creation": 0, 62 | "ddg_creation": 0, 63 | "cdg_creation": 0, 64 | "sources": 0, 65 | "constants": 1 66 | }, 67 | "4236888": { 68 | "sink_count": 1, 69 | "cfg_creation": 0, 70 | "ddg_creation": 0, 71 | "cdg_creation": 0, 72 | "sources": 0, 73 | "constants": 0 74 | }, 75 | "4245475": { 76 | "sink_count": 1, 77 | "cfg_creation": 0, 78 | "ddg_creation": 0, 79 | "cdg_creation": 0, 80 | "sources": 0, 81 | "constants": 1 82 | } 83 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-2022-26495/Recon.json: -------------------------------------------------------------------------------- 1 | { 2 | "cfg_creation": 1, 3 | "cfg_blocks": 2588, 4 | "cfg_edges": 4741, 5 | "recovered_functions": 421, 6 | "identified_functions": 10 7 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-2022-26495/UCSE.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 5, 3 | "4228751": { 4 | "entry_state": 1, 5 | "paths_found": 0, 6 | "paths_timedout": 0 7 | }, 8 | "4229729": { 9 | "checkpoint_state": 1, 10 | "paths_found": 1, 11 | "paths_timedout": 0, 12 | "exploration_time": 0, 13 | "expressions_tracked": 1, 14 | "filtered_expressions": 1, 15 | "sat_states": 1 16 | }, 17 | "4232332": { 18 | "entry_state": 1, 19 | "paths_found": 1, 20 | "paths_timedout": 0, 21 | "exploration_time": 2, 22 | "expressions_tracked": 15, 23 | "filtered_expressions": 1, 24 | "sat_states": 0 25 | }, 26 | "4232982": { 27 | "entry_state": 1, 28 | "paths_found": 2, 29 | "paths_timedout": 0, 30 | "expressions_tracked": 1, 31 | "filtered_expressions": 1, 32 | "sat_states": 0, 33 | "exploration_time": 0 34 | }, 35 | "4236888": { 36 | "entry_state": 1, 37 | "paths_found": 1, 38 | "paths_timedout": 0, 39 | "expressions_tracked": 10, 40 | "filtered_expressions": 10, 41 | "sat_states": 10 42 | } 43 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-xxxx-yyyy/DDA.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 1, 3 | "4205280": { 4 | "sink_count": 1, 5 | "cfg_creation": 0, 6 | "ddg_creation": 0, 7 | "cdg_creation": 0, 8 | "sources": 1, 9 | "constants": 0 10 | } 11 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-xxxx-yyyy/Recon.json: -------------------------------------------------------------------------------- 1 | { 2 | "cfg_creation": 1, 3 | "cfg_blocks": 2999, 4 | "cfg_edges": 5225, 5 | "recovered_functions": 630, 6 | "identified_functions": 1 7 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-xxxx-yyyy/UCSE.json: -------------------------------------------------------------------------------- 1 | { 2 | "identified_functions": 1, 3 | "4205280": { 4 | "checkpoint_state": 1, 5 | "paths_found": 1, 6 | "paths_timedout": 0, 7 | "exploration_time": 0, 8 | "expressions_tracked": 1, 9 | "filtered_expressions": 1, 10 | "sat_states": 1 11 | } 12 | } -------------------------------------------------------------------------------- /examples/cve-logs/cve-xxxx-yyyy/arbiter_vd_cve-xxxx-yyyy_cve-XXXX-YYYY.log: -------------------------------------------------------------------------------- 1 | 2022-04-06 15:56:07,968 - arbiter.master_chief.sa_recon - DEBUG - Creating CFG 2 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402600 3 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402620 4 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40262c 5 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402630 6 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402640 7 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402650 8 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402660 9 | 2022-04-06 15:56:09,660 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402670 10 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402680 11 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402690 12 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026a0 13 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026b0 14 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026c0 15 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026d0 16 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026e0 17 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4026f0 18 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402700 19 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402710 20 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402720 21 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402730 22 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402740 23 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402750 24 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402760 25 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402770 26 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402780 27 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402790 28 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027a0 29 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027b0 30 | 2022-04-06 15:56:09,661 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027c0 31 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027d0 32 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027e0 33 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4027f0 34 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402800 35 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402810 36 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402820 37 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402830 38 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402840 39 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402850 40 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402860 41 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402870 42 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402880 43 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402890 44 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028a0 45 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028b0 46 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028c0 47 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028d0 48 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028e0 49 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4028f0 50 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402900 51 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402910 52 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402920 53 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402930 54 | 2022-04-06 15:56:09,662 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402940 55 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402950 56 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402960 57 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402970 58 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402980 59 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402990 60 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029a0 61 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029b0 62 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029c0 63 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029d0 64 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029e0 65 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4029f0 66 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a00 67 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a10 68 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a20 69 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a30 70 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a40 71 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a50 72 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a60 73 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a70 74 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a80 75 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402a90 76 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402aa0 77 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ab0 78 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ac0 79 | 2022-04-06 15:56:09,663 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ad0 80 | 2022-04-06 15:56:09,664 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ae0 81 | 2022-04-06 15:56:09,664 - arbiter.master_chief.sa_recon - DEBUG - Finding ret block for setuid @ 0x402cca 82 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - DEBUG - Adding target function main:0x402ae0 83 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ed6 84 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ee0 85 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f0a 86 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f0b 87 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f10 88 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f42 89 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f87 90 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402f92 91 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fa0 92 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fb1 93 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fd1 94 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fda 95 | 2022-04-06 15:56:09,665 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fe0 96 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402fea 97 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ff0 98 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x402ffb 99 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403000 100 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403054 101 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4030ba 102 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4030f5 103 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403135 104 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40319e 105 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4031ba 106 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4031dc 107 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403203 108 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403223 109 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403236 110 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40324e 111 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403275 112 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4032a3 113 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4032b6 114 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4032ce 115 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4032ea 116 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40330f 117 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403310 118 | 2022-04-06 15:56:09,666 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403326 119 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403330 120 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403432 121 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40344d 122 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40346f 123 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403505 124 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403526 125 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403530 126 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403577 127 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403591 128 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4035a1 129 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4035b1 130 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4035c0 131 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4035ff 132 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403611 133 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403621 134 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403630 135 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403677 136 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40368a 137 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403690 138 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4037c7 139 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4037ff 140 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403827 141 | 2022-04-06 15:56:09,667 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403830 142 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4038bc 143 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4039e8 144 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4039f0 145 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403de9 146 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403e17 147 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403e56 148 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403e88 149 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x403f79 150 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404019 151 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40429e 152 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4045c4 153 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4045d0 154 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404654 155 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404672 156 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40469a 157 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4046a0 158 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4046ae 159 | 2022-04-06 15:56:09,668 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40470a 160 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40471e 161 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404739 162 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404740 163 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40478a 164 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404807 165 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404819 166 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404820 167 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40484c 168 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404850 169 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40485c 170 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404869 171 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404870 172 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4048ce 173 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4048d2 174 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4048e0 175 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4048e8 176 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4048f0 177 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40492b 178 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404930 179 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404949 180 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40497b 181 | 2022-04-06 15:56:09,669 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40499b 182 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4049a0 183 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4049f7 184 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a00 185 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a05 186 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a10 187 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a34 188 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a40 189 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a45 190 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a50 191 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a88 192 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404a90 193 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404afe 194 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404b00 195 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404bad 196 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404cc6 197 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404cd0 198 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404d81 199 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404da6 200 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404dd5 201 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404de0 202 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404e30 203 | 2022-04-06 15:56:09,670 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404e3a 204 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404e62 205 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404e70 206 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404e81 207 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404eba 208 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404ed6 209 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404ee0 210 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404f63 211 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404f70 212 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404fc6 213 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404fd0 214 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x404ff9 215 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405000 216 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405079 217 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405188 218 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40521f 219 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405232 220 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405258 221 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405357 222 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40560a 223 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4056ab 224 | 2022-04-06 15:56:09,671 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4056b0 225 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4056e6 226 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40575f 227 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4057a1 228 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4057ad 229 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4057b0 230 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405903 231 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4059a7 232 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4059b6 233 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4059da 234 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4059fa 235 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405a3b 236 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405a40 237 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405b0b 238 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405b63 239 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405b9e 240 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405bc5 241 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405be6 242 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405cfe 243 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405df5 244 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405e28 245 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405e30 246 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405e67 247 | 2022-04-06 15:56:09,672 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405e7b 248 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405e80 249 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405eac 250 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405ee3 251 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405eef 252 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405ef7 253 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405f00 254 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405f4e 255 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405f66 256 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405f88 257 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405fa7 258 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405fc7 259 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x405fd0 260 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406023 261 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406038 262 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40605e 263 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406060 264 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406125 265 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406211 266 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406243 267 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406261 268 | 2022-04-06 15:56:09,673 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406270 269 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4062d7 270 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40638f 271 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40639f 272 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40642d 273 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406484 274 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4064b3 275 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4064c0 276 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40652c 277 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40659a 278 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4065c1 279 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4065df 280 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406607 281 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406621 282 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40663f 283 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406640 284 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4066dd 285 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406719 286 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406754 287 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4067dd 288 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40693b 289 | 2022-04-06 15:56:09,674 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406973 290 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4069b4 291 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406a24 292 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406a47 293 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406a6e 294 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406aa9 295 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406ace 296 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406aee 297 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406afd 298 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406b0b 299 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406b2e 300 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406b4e 301 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406b68 302 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406b8e 303 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406bae 304 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406c08 305 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406c10 306 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406df7 307 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406e3a 308 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406e52 309 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406e73 310 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406e8a 311 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406ea2 312 | 2022-04-06 15:56:09,675 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406ebf 313 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x406ec0 314 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4070fb 315 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407344 316 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40739a 317 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4073db 318 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40743a 319 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407451 320 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407482 321 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40755d 322 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4075f1 323 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40774e 324 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407784 325 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4077f1 326 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40782d 327 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407846 328 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40787f 329 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40789c 330 | 2022-04-06 15:56:09,676 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40792e 331 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40797b 332 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4079a4 333 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407a2f 334 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407a54 335 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407aad 336 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407bbd 337 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407bd6 338 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407bfe 339 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407c38 340 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407c58 341 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407c6d 342 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407d2b 343 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407d41 344 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407d5e 345 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407d6f 346 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407d8f 347 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407da2 348 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407db5 349 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407dc5 350 | 2022-04-06 15:56:09,677 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x407e74 351 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408301 352 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408310 353 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40836a 354 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408370 355 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4083c5 356 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4083e4 357 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4083fa 358 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408400 359 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4085a6 360 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4085c2 361 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4085da 362 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4085f7 363 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408600 364 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40861b 365 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408692 366 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4086a0 367 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4086c8 368 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4086d7 369 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4086e6 370 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408715 371 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408732 372 | 2022-04-06 15:56:09,678 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408740 373 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40877f 374 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4087b2 375 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4087e2 376 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408809 377 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40881c 378 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40883a 379 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40884e 380 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408850 381 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4089b1 382 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4089c2 383 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408a16 384 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408b1e 385 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408b39 386 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408b74 387 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408b80 388 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x408c41 389 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409109 390 | 2022-04-06 15:56:09,679 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409134 391 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4091ba 392 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409269 393 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4092ad 394 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4092c2 395 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40946c 396 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40948d 397 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4094a6 398 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4094c3 399 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4094d3 400 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409612 401 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40965d 402 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40968d 403 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4096a4 404 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4096c2 405 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40971c 406 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40975c 407 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4097c5 408 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409852 409 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40986f 410 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409899 411 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x4098d6 412 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409a4b 413 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409a6e 414 | 2022-04-06 15:56:09,680 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409acf 415 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409ad0 416 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409aee 417 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b02 418 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b0d 419 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b10 420 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b31 421 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b40 422 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b5d 423 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b60 424 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409b87 425 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409bbc 426 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409bc0 427 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409bdc 428 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409bfe 429 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409c07 430 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409c10 431 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409ca9 432 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409cb0 433 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409d34 434 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409d53 435 | 2022-04-06 15:56:09,681 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409d60 436 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409d95 437 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409dbe 438 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409ddd 439 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e01 440 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e2d 441 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e38 442 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e5f 443 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e7a 444 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409e88 445 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409eb7 446 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409f0e 447 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409f30 448 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409fa8 449 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x409fb0 450 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a085 451 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a090 452 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a0f0 453 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a10a 454 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a110 455 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a126 456 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a130 457 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a132 458 | 2022-04-06 15:56:09,682 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a162 459 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a176 460 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a180 461 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a196 462 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a1a0 463 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a1d9 464 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a20c 465 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a215 466 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a220 467 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a24d 468 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a267 469 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a270 470 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a287 471 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a290 472 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a2a8 473 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a2d8 474 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a2e0 475 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a2f3 476 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a300 477 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a326 478 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a330 479 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a343 480 | 2022-04-06 15:56:09,683 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a350 481 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a365 482 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a370 483 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a386 484 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a390 485 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a3a8 486 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a3b0 487 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a422 488 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a434 489 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a440 490 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a5a4 491 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a5da 492 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a791 493 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a7ed 494 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a80e 495 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a88f 496 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a8aa 497 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a8fb 498 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a915 499 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a931 500 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a95b 501 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a968 502 | 2022-04-06 15:56:09,684 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a9eb 503 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40a9f0 504 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aa28 505 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aa30 506 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aab1 507 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aad8 508 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aaf4 509 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ab00 510 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ab13 511 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ab1d 512 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ab20 513 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ac37 514 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ac6a 515 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ac70 516 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ad09 517 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ad4c 518 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ad50 519 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40ae95 520 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40aefb 521 | 2022-04-06 15:56:09,685 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40af92 522 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40afd2 523 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b069 524 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b0bb 525 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b17b 526 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b1c5 527 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b1e9 528 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b228 529 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b264 530 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b272 531 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b285 532 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b2b7 533 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b2f9 534 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b323 535 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b358 536 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b451 537 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b4c8 538 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b538 539 | 2022-04-06 15:56:09,686 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b58c 540 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b5b7 541 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b5cc 542 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b5e6 543 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b692 544 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b6e7 545 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b754 546 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b7f6 547 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40b814 548 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bcbc 549 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bcc0 550 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bd19 551 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bd20 552 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bd38 553 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bd40 554 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bda5 555 | 2022-04-06 15:56:09,687 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bdb0 556 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x40bdb4 557 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700000 558 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700028 559 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700030 560 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700038 561 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700040 562 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700048 563 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700050 564 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700058 565 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700060 566 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700068 567 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700070 568 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700078 569 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700080 570 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700088 571 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700090 572 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700098 573 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000a0 574 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000a8 575 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000b0 576 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000b8 577 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000c0 578 | 2022-04-06 15:56:09,688 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000c8 579 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000d0 580 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000d8 581 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000e0 582 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000e8 583 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000f0 584 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7000f8 585 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700100 586 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700108 587 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700110 588 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700118 589 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700120 590 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700128 591 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700130 592 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700138 593 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700140 594 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700148 595 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700150 596 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700158 597 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700160 598 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700168 599 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700170 600 | 2022-04-06 15:56:09,689 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700178 601 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700180 602 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700188 603 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700190 604 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700198 605 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001a0 606 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001a8 607 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001b0 608 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001b8 609 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001c0 610 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001c8 611 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001d0 612 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001d8 613 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001e0 614 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001e8 615 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001f0 616 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x7001f8 617 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700200 618 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700208 619 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700210 620 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700218 621 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700220 622 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700228 623 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700230 624 | 2022-04-06 15:56:09,690 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700238 625 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700240 626 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700248 627 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700250 628 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700258 629 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700260 630 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700268 631 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x700270 632 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x801050 633 | 2022-04-06 15:56:09,691 - arbiter.master_chief.sa_recon - INFO - Starting recon of 0x801058 634 | 2022-04-06 15:56:09,692 - arbiter.master_chief.sa_advanced - DEBUG - Analysis of function @ 0x402ae0 635 | 2022-04-06 15:56:09,692 - arbiter.master_chief.sa_advanced - DEBUG - Creating CFGEmulated for function @ 0x402ae0 636 | 2022-04-06 15:56:10,302 - arbiter.master_chief.sa_advanced - DEBUG - Creating DDG for function @ 0x402ae0 (call_depth=1) 637 | 2022-04-06 15:56:10,498 - arbiter.master_chief.sa_advanced - DEBUG - Creating CDG for function @ 0x402ae0 638 | 2022-04-06 15:56:10,507 - arbiter.master_chief.sa_advanced - DEBUG - Starting back tracking for 0x402db3 639 | 2022-04-06 15:56:10,507 - arbiter.master_chief.sa_advanced - INFO - 1 sinks in function @ 0x402ae0 640 | 2022-04-06 15:56:10,509 - arbiter.master_chief.symbolic_execution - DEBUG - Creating checkpoint states for sub_402ae0 641 | 2022-04-06 15:56:10,509 - arbiter.master_chief.symbolic_execution - DEBUG - Adding checkpoint address setuid:0x402cd1 642 | 2022-04-06 15:56:10,512 - arbiter.master_chief.symbolic_execution - DEBUG - Hooked checkpoint setuid 643 | 2022-04-06 15:56:10,512 - arbiter.master_chief.symbolic_execution - DEBUG - Created 1 states 644 | 2022-04-06 15:56:10,512 - arbiter.master_chief.symbolic_execution - INFO - Starting exploration 0x402cd1 => 0x402db3 645 | 2022-04-06 15:56:10,513 - arbiter.master_chief.symbolic_execution - DEBUG - Watchdog started, waiting for 300s 646 | 2022-04-06 15:56:11,482 - arbiter.master_chief.symbolic_execution - DEBUG - Found 1 paths; active paths remaining 647 | 2022-04-06 15:56:11,483 - arbiter.master_chief.symbolic_execution - WARNING - Couldn't find expression in sym vars 648 | 2022-04-06 15:56:11,483 - arbiter.master_chief.symbolic_execution - INFO - Applying constraints for sink : EOF 649 | 2022-04-06 15:56:11,532 - arbiter.master_chief.symbolic_execution - INFO - Satisfied state : 0x0 650 | 2022-04-06 15:56:11,533 - arbiter.master_chief.symbolic_execution - DEBUG - Waiting for watchdog to join 651 | -------------------------------------------------------------------------------- /examples/cve-vuln_templates/vd_cve-2018-10388.py: -------------------------------------------------------------------------------- 1 | # 2 | # An example of a VD for CWE134 3 | # In this example, we target CVE-2018-10388 4 | # https://www.cvedetails.com/cve/CVE-2018-10388 5 | # 6 | # The vulnerability is a format string in the logMess function 7 | # The format string vulnerability can lead to memory corruption and possible arbitrary code execution 8 | # 9 | # void logMess(request *req, MYBYTE logLevel) { 10 | # ... 11 | # if (req->path[0]) 12 | # sprintf(logBuff, "Client %s:%u %s, %s\n", IP2String(tempbuff, req->client.sin_addr.s_addr), \ 13 | # ntohs(req->client.sin_port), req->path, req->serverError.errormessage); 14 | # else 15 | # sprintf(logBuff, "Client %s:%u, %s\n", IP2String(tempbuff, req->client.sin_addr.s_addr), \ 16 | # ntohs(req->client.sin_port), req->serverError.errormessage); 17 | # 18 | # syslog(LOG_MAKEPRI(LOG_LOCAL1, LOG_CRIT), logBuff); 19 | # ... 20 | # 21 | # The prototype of the syslog function is as follows 22 | # void syslog(int priority, const char *format, ...); 23 | # In this situation, an attacker can control the errormessage string and thereby control the format string used in syslog 24 | 25 | 26 | # 27 | # The VD that we can generate from this information is as follows 28 | # Sink := syslog(c, n) 29 | # Source := sprintf(n, c) 30 | # Constraint := `logBuff` should not be a constant string. 31 | # In this example, if we can identify a data-dependency between the sprintf and the syslog api's, it could lead to a vulnerability. 32 | # 33 | 34 | 35 | def apply_constraint(state, expr, init_val, **kwargs): 36 | # 37 | # Here, expr represents `logBuff`. 38 | # If logBuff was a constant string, the `addr` would contain the address of this string in the binary. 39 | # We then check if this address is part of the binary or not. 40 | # If the address is a part of the binary, it is a constant string and therefore cannot be controlled. 41 | # So we generate a constraint that we are sure will lead to an unsat state. 42 | # 43 | # Given that our source is sprintf, it is unlikely that we run into this problem of constant strings. 44 | # However, in order to be generic, we keep this constraint 45 | # 46 | addr = state.solver.eval(expr, cast_to=int) 47 | if state.project.loader.find_section_containing(addr) is not None: 48 | # Force an unsat error 49 | state.solver.add(expr==0) 50 | return 51 | 52 | 53 | def specify_sources(): 54 | # Our source here is sprintf 55 | # The first argument of sprintf is `logBuff`. 56 | return {'sprintf': 1} 57 | 58 | 59 | def specify_sinks(): 60 | # Note that the second argument of syslog denotes the format string to use. 61 | # This is similar to sprintf, dprintf, fprintf functions. 62 | maps = {'syslog': ['c', 'n']} 63 | return maps 64 | 65 | 66 | def save_results(reports): 67 | return 68 | -------------------------------------------------------------------------------- /examples/cve-vuln_templates/vd_cve-2022-26495.py: -------------------------------------------------------------------------------- 1 | # 2 | # An example of a VD for CWE131 3 | # In this example, we target CVE-2022-26495 4 | # https://nvd.nist.gov/vuln/detail/CVE-2022-26495 5 | # 6 | # The vulnerability is an integer overflow in handle_info function 7 | # inside nbd-server.c and exists in nbd upto 3.24 8 | # The integer overflow can lead to heap-based buffer overflow and possible arbitrary code execution 9 | # 10 | # 11 | # static bool handle_info(CLIENT* client, uint32_t opt, GArray* servers, uint32_t cflags) { 12 | # uint32_t namelen, len; 13 | # ... 14 | # socket_read(client, &namelen, sizeof(namelen)); 15 | # namelen = htonl(namelen); 16 | # ... 17 | # if(namelen > 0) { 18 | # name = malloc(namelen + 1); 19 | # name[namelen] = 0; 20 | # socket_read(client, name, namelen); 21 | # } 22 | # ... 23 | # } 24 | # The VD that we can generate from this information is as follows 25 | # Sink := malloc 26 | # Source := Return value of htonl 27 | # Constraint := Value passed to `malloc` should not be smaller than `namelen` 28 | # 29 | 30 | 31 | def apply_constraint(state, expr, init_val, **kwargs): 32 | # 33 | # Here, expr represents `namelen+1`. 34 | # The init_val can be represented a list of values that were combined to produce `namelen` 35 | # It can be visualized as : [namelen, 1] 36 | # However, since 1 is a constant, the actual init_val looks like : [namelen] 37 | # 38 | for x in init_val: 39 | if x.length < expr.length: 40 | x = x.zero_extend(expr.length-x.length) 41 | state.solver.add(expr < x) 42 | return 43 | 44 | 45 | def specify_sources(): 46 | # 47 | # Depending upon compiler flags, the call to `htonl` may be optimized away. 48 | # However, for this example, the binary has been compiled with the `-g` compilation flag 49 | # 50 | return {'htonl': 0} 51 | 52 | 53 | def specify_sinks(): 54 | # 55 | # Our sink is malloc just like the CWE131 module. 56 | # 57 | 58 | maps = {'malloc': ['n']} 59 | return maps 60 | 61 | 62 | def save_results(reports): 63 | return 64 | -------------------------------------------------------------------------------- /examples/cve-vuln_templates/vd_cve-xxxx-yyyy.py: -------------------------------------------------------------------------------- 1 | # 2 | # An example of a VD for CWE252 3 | # In this example, we do not have a CVE. 4 | # But we use the ping6 binary from inetutils package. 5 | # This bug was discovered during the evaluation of Arbiter 6 | # The vulnerability has now been fixed. 7 | # https://www.mail-archive.com/bug-inetutils@gnu.org/msg03149.html 8 | # 9 | # The vulnerability is an unchecked call to setuid in the main function 10 | # inside ping.c and has been fixed in commit 3ce348e63c3934958a2665ef8289d28a12150948 11 | # 12 | # int main (int argc, char **argv) { 13 | # ... 14 | # 15 | # setuid (getuid ()); 16 | # 17 | # ... 18 | # } 19 | # 20 | # The VD that we can generate from this information is as follows 21 | # Sink := End of function containing `setuid` 22 | # Source := Return value of `setuid` 23 | # Constraint := Return value of `setuid` must be constrained to either -1 or 0, but never satisfy both together. 24 | # 25 | # This CWE type is different from others because of the interesting constraint used. 26 | # To elaborate, imagine the following code. 27 | # 28 | # ... 29 | # int x = critical_function(); 30 | # if (x == ERROR_CODE) 31 | # return_value = -1; // A 32 | # else 33 | # return_value = 0; // B 34 | # 35 | # return return_value; // C 36 | # ... 37 | # 38 | # In this case, a state that reaches C could have either executed statement A or statement B. 39 | # Without more context, we cannot know whether this state is correctly handling a success/error case. 40 | # All we can say at C is : `x` == ERROR_CODE if A was executed or `x` != ERROR_CODE if B was executed. 41 | # Therefore a single state cannot satisfy the constraints `x` == ERROR_CODE and `x` != ERROR_CODE 42 | # 43 | # However, if the state does not check the return value, there will be no constraints on the return value. 44 | # In, such a state, the return value can be either success or error. 45 | # If we detect such a state, we can be sure (to an extent) that the error case is not handled at all. 46 | # 47 | 48 | 49 | def apply_constraint(state, expr, init_val, **kwargs): 50 | # 51 | # Here, `expr` represents the return value of `main`. 52 | # The return value of `setuid` will be present inside `init_val` 53 | # 54 | # 55 | # Our objective is to find a situation where one single state can satisfy error and success conditions. 56 | # Ideally, the best way to do this would be to add one constraint and check if its true. 57 | # Then, remove this first constraint and add the other and repeat the check. 58 | # However, removing the constraint from the state does not seem to remove it completely. 59 | # Therefore, we create a copy of the state. 60 | # 61 | s1 = state.copy() 62 | 63 | # 64 | # First we add the error constraint. 65 | # In this case, a return value of -1 indicates error. 66 | # `setuid` returns a 32 bit integer 67 | # So -1 in 32 bit is 0xFFFFFFFF 68 | # 69 | s1.solver.add(init_val[0] == 0xFFFFFFFF) 70 | if s1.satisfiable(): 71 | # 72 | # Now, we add the success constraint. 73 | # In this case, a return value of 0 indicates success. 74 | # 75 | state.solver.add(init_val[0] == 0) 76 | else: 77 | # 78 | state.solver.add(init_val[0] == 0xFFFFFFFF) 79 | return 80 | 81 | 82 | def specify_sources(): 83 | # 84 | # The source we're interested in is the return value of `setuid` 85 | # 86 | return {'setuid': 0} 87 | 88 | 89 | def specify_sinks(): 90 | # 91 | # Every function contains a ret instruction. 92 | # In order to filter it down, we focus on functions that contain the source. 93 | # Use 'r' to denote that we're interested in the ret instruction of the function containing `setuid`. 94 | # 95 | 96 | maps = {'setuid': ['r']} 97 | return maps 98 | 99 | 100 | def save_results(reports): 101 | return -------------------------------------------------------------------------------- /overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkrshnmenon/arbiter/0b55c19431015a1c259c3a94a6aca0c8d923c6a0/overview.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from pathlib import Path 3 | 4 | BASE_DIR = Path(__file__).resolve().parent 5 | 6 | setup( 7 | name='arbiter', 8 | python_requires=">=3.8", 9 | version='0.0.1', 10 | packages=find_packages(), 11 | description='A static+dynamic vulnerability detection tool', 12 | long_description=open(f'{BASE_DIR}/README.md').read(), 13 | install_requires=[ 14 | "angr==9.0.10576", 15 | "python-json-logger", 16 | "tqdm", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /test_files/README.md: -------------------------------------------------------------------------------- 1 | This directory is simply a sanity check to make sure things inside Arbiter work. 2 | 3 | As of right now, it only contains one target program (test.c) with three types of patterns. 4 | The `test_arbiter.py` is designed to identify these three patterns that are very specific to the test case. -------------------------------------------------------------------------------- /test_files/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int target_sink(int arg) { 4 | // do something important with arg 5 | return arg++; 6 | } 7 | 8 | 9 | void init_param(int *arg) { 10 | // initialize an argument passed as parameter 11 | *arg = 10; 12 | return; 13 | } 14 | 15 | 16 | int init_return_value() { 17 | // return a value when called 18 | return 10; 19 | } 20 | 21 | 22 | int entry_to_sink(int arg) { 23 | // data flow to be analyzed is from function entrypoint 24 | // (function argument in this case) to the sink. 25 | int tmp = arg + 10; 26 | return target_sink(tmp); 27 | } 28 | 29 | 30 | int source_param_to_sink() { 31 | // data flow to be analyzed is from argument passed to init_param 32 | // to the sink 33 | int arg = 0; 34 | init_param(&arg); 35 | int tmp = arg + 10; 36 | return target_sink(tmp); 37 | 38 | } 39 | 40 | 41 | int source_return_to_sink() { 42 | // data flow to be analyzed is from return value of init_return_value 43 | // to the sink 44 | int arg = init_return_value(); 45 | int tmp = arg + 10; 46 | return target_sink(tmp); 47 | } 48 | 49 | int main() { 50 | return 0; 51 | } -------------------------------------------------------------------------------- /test_files/test_arbiter.py: -------------------------------------------------------------------------------- 1 | import angr 2 | import logging 3 | 4 | from arbiter.master_chief import * 5 | 6 | logging.getLogger('arbiter.master_chief.sa_recon').setLevel(logging.INFO) 7 | logging.getLogger('arbiter.master_chief.sa_advanced').setLevel(logging.INFO) 8 | logging.getLogger('arbiter.master_chief.symbolic_execution').setLevel(logging.INFO) 9 | 10 | logging.getLogger('angr.storage.memory_mixins.default_filler_mixin').setLevel(logging.ERROR) 11 | 12 | def func_entry_to_sink(): 13 | """ 14 | The first pattern in Arbiter where the data flow is tracked from 15 | the function's entry point to the sink 16 | This function will match all 17 | """ 18 | def constrain(state, expr, init_val, site=None): 19 | """ 20 | Here, state is the angr state object currently stopped at the block 21 | where the target_sink is invoked. 22 | expr is the angr AST object of the argument of interest that will be passed to 23 | the target_sink 24 | init_val is a list of angr AST objects that correspond to the initial values 25 | that were combined to form the final expr AST. 26 | In this function, we can add constraints that try to prove the violation of some security property. 27 | """ 28 | return 29 | 30 | sinks = ['target_sink'] 31 | maps = {'target_sink': ['n']} 32 | 33 | project = angr.Project('./test.elf', auto_load_libs=False) 34 | 35 | sa = SA_Recon(project, sinks, maps) 36 | sa.analyze() 37 | assert len(sa.targets) == 3 38 | sb = SA_Adv(sa, call_depth=1, require_dd=True) 39 | sb.analyze_all() 40 | assert len(sb.targets) == 3 41 | se = SymExec(sb, constrain, require_dd=True) 42 | se.run_all() 43 | assert len(se.reports) == 3 44 | 45 | def func_param_to_sink(): 46 | """ 47 | The second pattern in Arbiter where the data flow is tracked from 48 | the parameter to an initialization function to the sink 49 | """ 50 | def constrain(state, expr, init_val, site=None): 51 | return 52 | 53 | sinks = ['target_sink'] 54 | maps = {'target_sink': ['n']} 55 | checkpoint = {'init_param': 1} 56 | 57 | project = angr.Project('./test.elf', auto_load_libs=False) 58 | 59 | sa = SA_Recon(project, sinks, maps) 60 | sa.analyze() 61 | assert len(sa.targets) == 3 62 | sb = SA_Adv(sa, checkpoint=checkpoint, require_dd=True, call_depth=1) 63 | sb.analyze_all() 64 | assert len(sb.targets) == 1 65 | se = SymExec(sb, constrain, require_dd=True) 66 | se.run_all() 67 | assert len(se.reports) == 1 68 | 69 | 70 | def func_return_to_sink(): 71 | """ 72 | The third pattern in Arbiter where the data flow is tracked from 73 | the return value of an initialization function to the sink 74 | """ 75 | def constrain(state, expr, init_val, site=None): 76 | return 77 | 78 | sinks = ['target_sink'] 79 | maps = {'target_sink': ['n']} 80 | checkpoint = {'init_return_value': 0} 81 | 82 | project = angr.Project('./test.elf', auto_load_libs=False) 83 | 84 | sa = SA_Recon(project, sinks, maps) 85 | sa.analyze() 86 | assert len(sa.targets) == 3 87 | sb = SA_Adv(sa, checkpoint=checkpoint, require_dd=True, call_depth=1) 88 | sb.analyze_all() 89 | assert len(sb.targets) == 1 90 | se = SymExec(sb, constrain, require_dd=True) 91 | se.run_all() 92 | assert len(se.reports) == 1 93 | 94 | if __name__ == '__main__': 95 | func_entry_to_sink() 96 | func_param_to_sink() 97 | func_return_to_sink() 98 | -------------------------------------------------------------------------------- /vuln_templates/CWE131.py: -------------------------------------------------------------------------------- 1 | def apply_constraint(state, expr, init_val, **kwargs): 2 | for x in init_val: 3 | if x.length > expr.length: 4 | continue 5 | if x.length < expr.length: 6 | x = x.zero_extend(expr.length-x.length) 7 | s1 = state.copy() 8 | s1.solver.add(expr > x) 9 | # Check whether we can actually increment the value 10 | if s1.satisfiable(): 11 | # Now if expr can be GT and LT x, it means there's an integer overflow/underflow 12 | state.solver.add(expr < x) 13 | else: 14 | # Unsat the whole thing 15 | state.solver.add(expr > x) 16 | return 17 | 18 | 19 | def specify_sinks(): 20 | maps = {'malloc': ['n'], 21 | 'calloc': ['n'], 22 | 'realloc': ['c', 'n']} 23 | 24 | return maps 25 | 26 | 27 | def specify_sources(): 28 | return {} 29 | 30 | def save_results(reports): 31 | for r in reports: 32 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 33 | f.write("\n".join(str(x) for x in r.bbl_history)) 34 | -------------------------------------------------------------------------------- /vuln_templates/CWE134.py: -------------------------------------------------------------------------------- 1 | def apply_constraint(state, expr, init_val, **kwargs): 2 | addr = state.solver.eval(expr, cast_to=int) 3 | if state.project.loader.find_section_containing(addr) is not None: 4 | # Force an unsat error 5 | state.solver.add(expr==0) 6 | return 7 | 8 | 9 | def specify_sinks(): 10 | maps = {'printf': ['n'], 11 | 'fprintf': ['c', 'n'], 12 | 'dprintf': ['c', 'n'], 13 | 'sprintf': ['c', 'n'], 14 | 'vasprintf': ['c', 'n'], 15 | 'snprintf': ['c', 'c', 'n'], 16 | 'fprintf_chk': ['c', 'c', 'n'], 17 | 'dprintf_chk': ['c', 'c', 'n'], 18 | 'sprintf_chk': ['c', 'c', 'c', 'n'], 19 | 'vasprintf_chk': ['c', 'c', 'n'], 20 | 'asprintf_chk': ['c', 'c', 'n'], 21 | 'snprintf_chk': ['c', 'c', 'c', 'c', 'n'], 22 | } 23 | 24 | return maps 25 | 26 | 27 | def specify_sources(): 28 | return {} 29 | 30 | 31 | def save_results(reports): 32 | for r in reports: 33 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 34 | f.write("\n".join(str(x) for x in r.bbl_history)) 35 | -------------------------------------------------------------------------------- /vuln_templates/CWE190_juliet_signed.py: -------------------------------------------------------------------------------- 1 | def apply_constraint(state, expr, init_val, **kwargs): 2 | site = kwargs['site'] 3 | for x in init_val: 4 | if x.length < expr.length: 5 | x = x.sign_extend(expr.length-x.length) 6 | if site.callee == 'printHexCharLine': 7 | x = x[7:0] 8 | expr = expr[7:0] 9 | elif site.callee == 'printIntLine': 10 | x = x[31:0] 11 | expr = expr[31:0] 12 | state.solver.add(expr.SLT(x)) 13 | 14 | 15 | def specify_sinks(): 16 | sinks = [ 17 | 'printIntLine', 18 | 'printHexCharLine', 19 | 'printLongLongLine', 20 | ] 21 | maps = {x: ['n'] for x in sinks} 22 | return maps 23 | 24 | 25 | def specify_sources(): 26 | checkpoints = {'atoi': 0, 27 | 'rand': 0, 28 | 'fscanf': 3, 29 | 'badSource': 0} 30 | 31 | return checkpoints 32 | 33 | def save_results(reports): 34 | for r in reports: 35 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 36 | f.write("\n".join(str(x) for x in r.bbl_history)) 37 | -------------------------------------------------------------------------------- /vuln_templates/CWE190_juliet_unsigned.py: -------------------------------------------------------------------------------- 1 | def constrain(state, expr, init_val, **kwargs): 2 | for x in init_val: 3 | x = x[31:] 4 | expr = expr[31:] 5 | if x.length < expr.length: 6 | x = x.zero_extend(expr.length-x.length) 7 | state.solver.add(expr < x) 8 | 9 | 10 | def specify_sinks(): 11 | sinks = [ 12 | 'printUnsignedLine', 13 | ] 14 | maps = {x: ['n'] for x in sinks} 15 | 16 | return maps 17 | 18 | 19 | def specify_sources(): 20 | checkpoints = {'atoi': 0, 21 | 'rand': 0, 22 | 'fscanf': 3, 23 | 'badSource': 0} 24 | 25 | return checkpoints 26 | 27 | 28 | def save_results(reports): 29 | for r in reports: 30 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 31 | f.write("\n".join(str(x) for x in r.bbl_history)) 32 | -------------------------------------------------------------------------------- /vuln_templates/CWE252.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | SYSCALL_TABLE = "syscalls_annotated.json" 5 | 6 | 7 | def parse_syscalls(syscall_table, return_filter=None): 8 | maps = {} 9 | checkpoints = {} 10 | syscalls = {} 11 | 12 | with open(syscall_table) as f: 13 | syscalls = json.load(f) 14 | 15 | for syscall, s_info in syscalls.items(): 16 | ret = s_info['ret'] 17 | if not ret: 18 | continue 19 | if return_filter != None: 20 | values = ret['values'] 21 | if str(return_filter) not in values or values[str(return_filter)] != 'error': 22 | continue 23 | print(f"syscall: {syscall}") 24 | maps[syscall] = ['r'] 25 | checkpoints[syscall] = 0 26 | 27 | return maps, checkpoints 28 | 29 | 30 | def apply_constraint(state, expr, init_val, **kwargs): 31 | s1 = state.copy() 32 | # target function returned -1 (indicating error) 33 | s1.solver.add(init_val[0] == 0xffffffffffffffff) 34 | if s1.satisfiable(): 35 | # target function allows both (indicating absence of checks) 36 | state.solver.add(init_val[0] == 0) 37 | else: 38 | # Unsat the whole thing 39 | state.solver.add(init_val[0] == 0xffffffffffffffff) 40 | return 41 | 42 | 43 | def specify_sinks(): 44 | maps, _ = parse_syscalls(SYSCALL_TABLE, return_filter=-1) 45 | return maps 46 | 47 | 48 | def specify_sources(): 49 | _, checkpoints = parse_syscalls(SYSCALL_TABLE, return_filter=-1) 50 | return checkpoints 51 | 52 | 53 | def save_results(reports): 54 | for r in reports: 55 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 56 | f.write("\n".join(str(x) for x in r.bbl_history)) 57 | -------------------------------------------------------------------------------- /vuln_templates/CWE337.py: -------------------------------------------------------------------------------- 1 | def apply_constraint(state, expr, init_val, **kwargs): 2 | return 3 | 4 | 5 | def specify_sinks(): 6 | maps = {'srand': ['n']} 7 | return maps 8 | 9 | 10 | def specify_sources(): 11 | checkpoints = {'time': 0} 12 | return checkpoints 13 | 14 | 15 | def save_results(reports): 16 | for r in reports: 17 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 18 | f.write("\n".join(str(x) for x in r.bbl_history)) -------------------------------------------------------------------------------- /vuln_templates/CWE680_juliet.py: -------------------------------------------------------------------------------- 1 | def apply_constraint(state, expr, init_val, **kwargs): 2 | for x in init_val: 3 | if x.length < expr.length: 4 | x = x.zero_extend(expr.length-x.length) 5 | state.solver.add(expr < x) 6 | 7 | 8 | def specify_sinks(): 9 | maps = {'malloc': ['n'], 'operator new': ['n']} 10 | return maps 11 | 12 | 13 | def specify_sources(): 14 | checkpoints = {'atoi': 0, 15 | 'rand': 0, 16 | 'fscanf': 3, 17 | 'badSource': 0} 18 | 19 | return checkpoints 20 | 21 | 22 | def save_results(reports): 23 | for r in reports: 24 | with open(f"ArbiterReport_{hex(r.bbl)}", "w") as f: 25 | f.write("\n".join(str(x) for x in r.bbl_history)) 26 | -------------------------------------------------------------------------------- /vuln_templates/README.md: -------------------------------------------------------------------------------- 1 | This is where all the VD's used during the Arbiter evaluation reside. 2 | 3 | 4 | The files CWE131.py, CWE134.py, CWE252.py and CWE337.py correspond to CWE types CWE-131, CWE-134, CWE-252 and CWE-337 respectively. 5 | 6 | 7 | The CWE680_juliet.py is the template that was used to evaluate the Juliet Test Suite for CWE680. 8 | 9 | 10 | The files CWE190_juliet_signed.py and CWE190_juliet_unsigned.py are the two templates used to evaluate the Juliet Test Suite for CWE190. 11 | 12 | Please refer to the Arbiter paper for explanation on why we had to split the Juliet Test Suite for CWE190 into signed and unsigned. 13 | 14 | 15 | # How to run 16 | 17 | The `run_arbiter.py` is a handy entry point that calls the Arbiter API's, sets up logging and other miscellaneous tasks. 18 | 19 | The arguments that can be passed to `run_arbiter.py` are as follows 20 | 21 | ``` 22 | $ run_arbiter.py -h 23 | usage: run_arbiter.py [-h] -f VD -t TARGET [-r LEVEL] [-l LOG_DIR] [-j JSON_DIR] [-s] 24 | 25 | Use Arbiter to run a template against a specific binary 26 | 27 | optional arguments: 28 | -h, --help show this help message and exit 29 | -f VD The VD template to use 30 | -t TARGET The target binary to analyze 31 | -r LEVEL Number of levels for Adaptive False Positive Reduction 32 | -l LOG_DIR Enable logging to LOG_DIR 33 | -j JSON_DIR Enable verbose statistics dumps to JSON_DIR 34 | -s Enable strict mode (stricter static data-flow based filtering) 35 | 36 | ``` 37 | 38 | The parameters `-f` and `-t` are required while the others are optional. 39 | 40 | 41 | An example of running the VD for CWE-131 for the `ls` binary would be as follows 42 | 43 | ``` 44 | mkdir 45 | mkdir 46 | cd /vuln_templates/ 47 | ./run_arbiter.py -f ./CWE131.py -t /bin/ls -l -j 48 | ``` 49 | 50 | # Writing your own VD 51 | 52 | In order to write a new VD, all you need to do is to implement 4 functions, namely 53 | `apply_constraint`, `specify_sources`, `specify_sinks` and `save_results`. 54 | 55 | Please refer to the `examples` directory for more information about each of these functions. 56 | 57 | 58 | Once you have this VD ready, invoke the `run_arbiter` with the `-f` parameter pointing to this VD and the `-t` parameter pointing to the target binary. 59 | 60 | -------------------------------------------------------------------------------- /vuln_templates/kubernetes_wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage () { 4 | echo "Usage : $0 -f -t [ -r ]" 5 | echo -e " -f VD\t\t: The VD inside vuln_templates to use" 6 | echo -e " -t TARGET\t: The path to the target binary" 7 | echo -e " -r LEVEL\t: The level of Adaptive FP reduction" 8 | echo "" 9 | exit 0 10 | } 11 | 12 | 13 | VD=${VD:-} 14 | TARGET=${TARGET:-} 15 | LEVEL=${LEVEL:--1} 16 | 17 | LOG_DIR=$HOME/logs 18 | NFS_DIR=/shared/arbiter/dataset 19 | TEMPLATE_DIR=$(realpath $(dirname $0)) 20 | 21 | RUNNER=$TEMPLATE_DIR/run_arbiter.py 22 | 23 | 24 | while getopts "f:t:r:" OPTION; do 25 | case $OPTION in 26 | f) 27 | VD=$OPTARG 28 | ;; 29 | t) 30 | TARGET=$OPTARG 31 | ;; 32 | r) 33 | LEVEL=$OPTARG 34 | ;; 35 | *|h) 36 | usage 37 | ;; 38 | esac 39 | done 40 | 41 | if [ -z "$VD" ]; then 42 | echo "[!] Error : -f option has to be specified" 43 | usage 44 | elif [ -z "$TARGET" ]; then 45 | echo "[!] Error : -t option has to be specified" 46 | usage 47 | fi 48 | 49 | VD_PATH=$TEMPLATE_DIR/$VD 50 | BIN_PATH=$NFS_DIR/$TARGET 51 | 52 | if [ ! -f "$VD_PATH" ]; then 53 | echo "[!] Error : $VD_PATH does not exist" 54 | exit 1 55 | elif [ ! -f "$BIN_PATH" ]; then 56 | echo "[!] Error : $BIN_PATH does not exist" 57 | exit 1 58 | fi 59 | 60 | cd $LOG_DIR 61 | 62 | if [ -n "$LEVEL" ]; then 63 | $RUNNER -f $VD_PATH -t $BIN_PATH -l $LOG_DIR -j $LOG_DIR -r $LEVEL 64 | else 65 | $RUNNER -f $VD_PATH -t $BIN_PATH -l $LOG_DIR -j $LOG_DIR 66 | fi 67 | 68 | if [ -z "$LEVEL" ]; then 69 | LEVEL="N" 70 | fi 71 | 72 | PKG=$(echo $TARGET |cut -d'/' -f1) 73 | LOG_PATH="$NFS_DIR/$PKG/${VD%.py}_${LEVEL}_logs" 74 | 75 | cp -r $LOG_DIR $LOG_PATH 76 | -------------------------------------------------------------------------------- /vuln_templates/run_arbiter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import angr 4 | import string 5 | import logging 6 | 7 | from pathlib import Path 8 | from importlib import util 9 | from argparse import ArgumentParser 10 | 11 | from arbiter.master_chief import * 12 | 13 | 14 | LOG_DIR = None 15 | JSON_DIR = None 16 | CALL_DEPTH = 1 17 | STRICT_MODE = False 18 | IDENTIFIER = None 19 | LOG_LEVEL = logging.DEBUG 20 | CALLER_LEVEL = -1 21 | 22 | logging.getLogger('angr').setLevel(logging.CRITICAL) 23 | 24 | 25 | def enable_logging(vd, target): 26 | vd = Path(vd).stem 27 | target = Path(target).stem 28 | 29 | loggers = ['sa_recon', 'sa_advanced', 'symbolic_execution'] 30 | for logger in loggers: 31 | l = logging.getLogger(f"arbiter.master_chief.{logger}") 32 | 33 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 34 | if LOG_DIR is not None: 35 | handler = logging.FileHandler(f"{LOG_DIR}/arbiter_{vd}_{target}.log") 36 | handler.setFormatter(formatter) 37 | l.addHandler(handler) 38 | 39 | l.setLevel(LOG_LEVEL) 40 | 41 | 42 | def main(template, target): 43 | project = angr.Project(target, auto_load_libs=False) 44 | 45 | sink_map = template.specify_sinks() 46 | sa = SA_Recon(project, sinks=sink_map.keys(), maps=sink_map, json_dir=JSON_DIR) 47 | if IDENTIFIER is None: 48 | sa.analyze(ignore_funcs=BLACKLIST) 49 | else: 50 | sa.analyze_one(IDENTIFIER) 51 | 52 | sources = template.specify_sources() 53 | sb = SA_Adv(sa, checkpoint=sources, require_dd=STRICT_MODE, call_depth=CALL_DEPTH, json_dir=JSON_DIR) 54 | sb.analyze_all() 55 | 56 | constrain = template.apply_constraint 57 | se = SymExec(sb, constrain=constrain, require_dd=STRICT_MODE, json_dir=JSON_DIR) 58 | se.run_all() 59 | 60 | template.save_results(se.postprocessing(pred_level=CALLER_LEVEL)) 61 | 62 | 63 | if __name__ == '__main__': 64 | parser = ArgumentParser(description='Use Arbiter to run a template against a specific binary') 65 | parser.add_argument('-f', metavar='VD', type=str, help='The VD template to use', required=True) 66 | parser.add_argument('-t', metavar='TARGET', type=str, help='The target binary to analyze', required=True) 67 | parser.add_argument('-i', metavar='ADDR', type=str, help='Specify a target function identifier (name|addr) to focus the analysis on', required=False, default="") 68 | parser.add_argument('-b', metavar='BLACKLIST', type=str, help='Specify a list of function identifiers (name|addr) to skip analysis', required=False, default=[], nargs="+") 69 | parser.add_argument('-r', metavar='LEVEL', type=int, help='Number of levels for Adaptive False Positive Reduction', required=False, default=-1) 70 | parser.add_argument('-l', metavar='LOG_DIR', type=str, help='Enable logging to LOG_DIR', required=False) 71 | parser.add_argument('-j', metavar='JSON_DIR', type=str, help='Enable verbose statistics dumps to JSON_DIR', required=False) 72 | parser.add_argument('-s', help='Enable strict mode (stricter static data-flow based filtering)', action='store_true', required=False) 73 | 74 | args = parser.parse_args() 75 | 76 | vd = Path(args.f) 77 | target = Path(args.t) 78 | 79 | if vd.exists() is False: 80 | sys.stderr.write(f"Error: {vd} does not exist\n") 81 | sys.exit(-1) 82 | elif target.exists() is False: 83 | sys.stderr.write(f"Error: {target} does not exist\n") 84 | sys.exit(-1) 85 | 86 | try: 87 | spec = util.spec_from_file_location(vd.stem, vd.absolute().as_posix()) 88 | template = util.module_from_spec(spec) 89 | spec.loader.exec_module(template) 90 | except: 91 | sys.stderr.write(f"Error could not import VD: {vd}\n") 92 | sys.exit(-1) 93 | 94 | if len(args.i) == 0: 95 | IDENTIFIER = None 96 | elif args.i.isdecimal(): 97 | IDENTIFIER = int(args.i) 98 | elif args.i.startswith('0x') or all(c in string.hexdigits for c in args.i): 99 | IDENTIFIER = int(args.i, 16) 100 | else: 101 | IDENTIFIER = args.i 102 | 103 | BLACKLIST = args.b 104 | 105 | CALLER_LEVEL = args.r 106 | 107 | if args.l: 108 | Path(args.l).mkdir(parents=True, exist_ok=True) 109 | if Path(args.l).exists(): 110 | LOG_DIR = Path(args.l).resolve().as_posix() 111 | else: 112 | sys.stderr.write(f"Directory {args.l} does not exist and we could not create it\n") 113 | enable_logging(vd, target) 114 | 115 | if args.j: 116 | Path(args.j).mkdir(parents=True, exist_ok=True) 117 | if Path(args.j).exists(): 118 | JSON_DIR = Path(args.j).resolve().as_posix() 119 | else: 120 | sys.stderr.write(f"Directory {args.l} does not exist and we could not create it\n") 121 | 122 | if args.s: 123 | STRICT_MODE = True 124 | 125 | main(template, target) 126 | -------------------------------------------------------------------------------- /vuln_templates/syscalls_annotated.json: -------------------------------------------------------------------------------- 1 | { 2 | "setuid": { 3 | "args": [ 4 | { 5 | "values": {}, 6 | "type": "integer" 7 | } 8 | ], 9 | "ret": { 10 | "values": { 11 | "0": "success", 12 | "-1": "error" 13 | }, 14 | "type": "integer" 15 | } 16 | }, 17 | "chdir": { 18 | "args": [ 19 | { 20 | "values": {}, 21 | "type": "pointer" 22 | } 23 | ], 24 | "ret": { 25 | "values": { 26 | "0": "success", 27 | "-1": "error" 28 | }, 29 | "type": "integer" 30 | } 31 | }, 32 | "setpgid": { 33 | "args": [ 34 | { 35 | "values": {}, 36 | "type": "integer" 37 | }, 38 | { 39 | "values": {}, 40 | "type": "integer" 41 | } 42 | ], 43 | "ret": { 44 | "values": { 45 | "0": "success", 46 | "-1": "error" 47 | }, 48 | "type": "integer" 49 | } 50 | }, 51 | "mmap": { 52 | "args": [ 53 | { 54 | "values": { 55 | "NULL": "the kernel chooses address" 56 | }, 57 | "type": "pointer" 58 | }, 59 | { 60 | "values": {}, 61 | "type": "integer" 62 | }, 63 | { 64 | "values": {}, 65 | "type": "integer" 66 | }, 67 | { 68 | "values": {}, 69 | "type": "integer" 70 | }, 71 | { 72 | "values": {}, 73 | "type": "integer" 74 | }, 75 | { 76 | "values": {}, 77 | "type": "integer" 78 | } 79 | ], 80 | "ret": { 81 | "values": { 82 | ">0": "success", 83 | "-1": "error" 84 | }, 85 | "type": "pointer" 86 | } 87 | }, 88 | "setreuid": { 89 | "args": [ 90 | { 91 | "values": { 92 | "-1": "ID is not changed" 93 | }, 94 | "type": "integer" 95 | }, 96 | { 97 | "values": { 98 | "-1": "ID is not changed" 99 | }, 100 | "type": "integer" 101 | } 102 | ], 103 | "ret": { 104 | "values": { 105 | "0": "success", 106 | "-1": "error" 107 | }, 108 | "type": "integer" 109 | } 110 | }, 111 | "chown": { 112 | "args": [ 113 | { 114 | "values": {}, 115 | "type": "pointer" 116 | }, 117 | { 118 | "values": { 119 | "-1": "ID is not changed" 120 | }, 121 | "type": "integer" 122 | }, 123 | { 124 | "values": { 125 | "-1": "ID is not changed" 126 | }, 127 | "type": "integer" 128 | } 129 | ], 130 | "ret": { 131 | "values": { 132 | "0": "success", 133 | "-1": "error" 134 | }, 135 | "type": "integer" 136 | } 137 | }, 138 | "access": { 139 | "args": [ 140 | { 141 | "values": {}, 142 | "type": "pointer" 143 | }, 144 | { 145 | "values": {}, 146 | "type": "integer" 147 | } 148 | ], 149 | "ret": { 150 | "values": { 151 | "0": "success", 152 | "-1": "error" 153 | }, 154 | "type": "integer" 155 | } 156 | }, 157 | "setsid": { 158 | "args": [ 159 | { 160 | "values": {}, 161 | "type": "void" 162 | } 163 | ], 164 | "ret": { 165 | "values": { 166 | "-1": "error", 167 | ">=0": "success" 168 | }, 169 | "type": "integer" 170 | } 171 | }, 172 | "chroot": { 173 | "args": [ 174 | { 175 | "values": {}, 176 | "type": "pointer" 177 | } 178 | ], 179 | "ret": { 180 | "values": { 181 | "0": "success", 182 | "-1": "error" 183 | }, 184 | "type": "integer" 185 | } 186 | }, 187 | "setregid": { 188 | "args": [ 189 | { 190 | "values": { 191 | "-1": "ID is not changed" 192 | }, 193 | "type": "integer" 194 | }, 195 | { 196 | "values": { 197 | "-1": "ID is not changed" 198 | }, 199 | "type": "integer" 200 | } 201 | ], 202 | "ret": { 203 | "values": { 204 | "0": "success", 205 | "-1": "error" 206 | }, 207 | "type": "integer" 208 | } 209 | }, 210 | "setgid": { 211 | "args": [ 212 | { 213 | "values": {}, 214 | "type": "integer" 215 | } 216 | ], 217 | "ret": { 218 | "values": { 219 | "0": "success", 220 | "-1": "error" 221 | }, 222 | "type": "integer" 223 | } 224 | }, 225 | "prctl": { 226 | "args": [ 227 | { 228 | "values": {}, 229 | "type": "integer" 230 | }, 231 | { 232 | "values": {}, 233 | "type": "integer" 234 | }, 235 | { 236 | "values": {}, 237 | "type": "integer" 238 | }, 239 | { 240 | "values": {}, 241 | "type": "integer" 242 | }, 243 | { 244 | "values": {}, 245 | "type": "integer" 246 | } 247 | ], 248 | "ret": { 249 | "values": { 250 | "-1": "error", 251 | ">=0": "success" 252 | }, 253 | "type": "integer" 254 | } 255 | }, 256 | "setresgid": { 257 | "args": [ 258 | { 259 | "values": { 260 | "-1": "ID is not changed" 261 | }, 262 | "type": "integer" 263 | }, 264 | { 265 | "values": { 266 | "-1": "ID is not changed" 267 | }, 268 | "type": "integer" 269 | }, 270 | { 271 | "values": { 272 | "-1": "ID is not changed" 273 | }, 274 | "type": "integer" 275 | } 276 | ], 277 | "ret": { 278 | "values": { 279 | "0": "success", 280 | "-1": "error" 281 | }, 282 | "type": "integer" 283 | } 284 | }, 285 | "setresuid": { 286 | "args": [ 287 | { 288 | "values": { 289 | "-1": "ID is not changed" 290 | }, 291 | "type": "integer" 292 | }, 293 | { 294 | "values": { 295 | "-1": "ID is not changed" 296 | }, 297 | "type": "integer" 298 | }, 299 | { 300 | "values": { 301 | "-1": "ID is not changed" 302 | }, 303 | "type": "integer" 304 | } 305 | ], 306 | "ret": { 307 | "values": { 308 | "0": "success", 309 | "-1": "error" 310 | }, 311 | "type": "integer" 312 | } 313 | } 314 | } --------------------------------------------------------------------------------