1# coding=utf-8 2# Copyright 2018 Sascha Schirra 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are met: 6# 7# 1. Redistributions of source code must retain the above copyright notice, this 8# list of conditions and the following disclaimer. 9# 10# 2. Redistributions in binary form must reproduce the above copyright notice, 11# this list of conditions and the following disclaimer in the documentation 12# and/or other materials provided with the distribution. 13# 14# 3. Neither the name of the copyright holder nor the names of its contributors 15# may be used to endorse or promote products derived from this software without 16# specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" A ND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29from ropper.gadget import Category, Gadget 30from ropper.common.error import * 31from ropper.common.utils import * 32from ropper.rop import Ropper 33from ropper.arch import x86_64 34from ropper.ropchain.ropchain import * 35from ropper.loaders.loader import Type 36from ropper.loaders.elf import ELF 37from ropper.loaders.pe import PE 38from ropper.loaders.raw import Raw 39from ropper.loaders.mach_o import MachO 40from re import match 41import itertools 42import math 43import sys 44 45if sys.version_info.major == 2: 46 range = xrange 47 48class RopChainX86_64(RopChain): 49 50 MAX_QUALI = 7 51 52 def _printHeader(self): 53 toReturn = '' 54 toReturn += ('#!/usr/bin/env python\n') 55 toReturn += ('# Generated by ropper ropchain generator #\n') 56 toReturn += ('from struct import pack\n') 57 toReturn += ('\n') 58 toReturn += ('p = lambda x : pack(\'Q\', x)\n') 59 60 toReturn += ('\n') 61 62 return toReturn 63 64 def _printRebase(self): 65 toReturn = '' 66 67 for binary,section in self._usedBinaries: 68 imageBase = Gadget.IMAGE_BASES[binary] 69 toReturn += ('IMAGE_BASE_%d = %s # %s\n' % (self._usedBinaries.index((binary, section)),toHex(imageBase ,8), binary)) 70 toReturn += ('rebase_%d = lambda x : p(x + IMAGE_BASE_%d)\n\n'% (self._usedBinaries.index((binary, section)),self._usedBinaries.index((binary, section)))) 71 return toReturn 72 73 @classmethod 74 def name(cls): 75 return '' 76 77 @classmethod 78 def availableGenerators(cls): 79 return [RopChainSystemX86_64, RopChainMprotectX86_64] 80 81 @classmethod 82 def archs(self): 83 return [x86_64] 84 85 def _createDependenceChain(self, gadgets): 86 """ 87 gadgets - list with tuples 88 89 tuple contains: 90 - method to create chaingadget 91 - list with arguments 92 - dict with named arguments 93 - list with registers which are not allowed to override in the gadget 94 """ 95 failed = [] 96 cur_len = 0 97 cur_chain = '' 98 counter = 0 99 100 max_perm = math.factorial(len(gadgets)) 101 for x in itertools.permutations(gadgets): 102 counter += 1 103 self._printMessage('[*] Try permuation %d / %d' % (counter, max_perm)) 104 found = False 105 for y in failed: 106 107 if x[:len(y)] == y: 108 found = True 109 break 110 if found: 111 continue 112 try: 113 fail = [] 114 chain2 = '' 115 dontModify = [] 116 badRegs = [] 117 c = 0 118 for idx in range(len(x)): 119 g = x[idx] 120 if idx != 0: 121 badRegs.extend(x[idx-1][3]) 122 123 dontModify.extend(g[3]) 124 fail.append(g) 125 chain2 += g[0](*g[1], badRegs=badRegs, dontModify=dontModify,**g[2])[0] 126 127 128 cur_chain += chain2 129 break 130 131 except RopChainError as e: 132 pass 133 if len(fail) > cur_len: 134 cur_len = len(fail) 135 cur_chain = '# Filled registers: ' 136 for fa in fail[:-1]: 137 138 cur_chain += (fa[2]['reg']) + ', ' 139 cur_chain += '\n' 140 cur_chain += chain2 141 142 failed.append(tuple(fail)) 143 else: 144 self._printMessage('') 145 self._printMessage('Cannot create chain which fills all registers') 146 self._printMessage('') 147 return cur_chain 148 149 def _isModifiedOrDereferencedAccess(self, gadget, dontModify): 150 151 regs = [] 152 for line in gadget.lines[1:]: 153 line = line[1] 154 if '[' in line: 155 return True 156 if dontModify: 157 m = match('[a-z]+ (e?[abcds][ixlh]),?.*', line) 158 if m and m.group(1) in dontModify: 159 return True 160 161 return False 162 163 164 165 def _paddingNeededFor(self, gadget): 166 regs = [] 167 for idx in range(1,len(gadget.lines)): 168 line = gadget.lines[idx][1] 169 matched = match('^pop (...)$', line) 170 if matched: 171 regs.append(matched.group(1)) 172 return regs 173 174 175 def _printRopInstruction(self, gadget, padding=True, value=None): 176 toReturn = ('rop += rebase_%d(%s) # %s\n' % (self._usedBinaries.index((gadget.fileName, gadget.section)),toHex(gadget.lines[0][0],8), gadget.simpleString())) 177 178 value_first = False 179 180 if padding: 181 regs = self._paddingNeededFor(gadget) 182 183 if len(regs) > 0: 184 dst = gadget.category[2]['dst'] 185 search = '^pop (%s)$' % dst 186 first_line = gadget.lines[0][1] 187 if match(search, first_line): 188 value_first = True 189 190 padding_str = '' 191 for i in range(len(regs)): 192 padding_str +=self._printPaddingInstruction() 193 194 if value_first: 195 toReturn += value 196 toReturn += padding_str 197 else: 198 toReturn += padding_str 199 if value: 200 toReturn += value 201 202 return toReturn 203 204 def _printAddString(self, string): 205 return ('rop += \'%s\'\n' % string) 206 207 def _printRebasedAddress(self, addr, comment='', idx=0): 208 return ('rop += rebase_%d(%s)\n' % (idx,addr)) 209 210 def _printPaddingInstruction(self, addr='0xdeadbeefdeadbeef'): 211 return ('rop += p(%s)\n' % addr) 212 213 def _containsZeroByte(self, addr): 214 return self.containsBadbytes(addr,8) 215 216 def _createZeroByteFillerForSub(self, number): 217 start = 0x0101010101010101 218 for i in range(start, 0x0202020202020202): 219 if not self._containsZeroByte(i) and not self._containsZeroByte(i+number): 220 return i 221 222 def _createZeroByteFillerForAdd(self, number): 223 start = 0x0101010101010101 224 for i in range(start, 0x0202020202020202): 225 if not self._containsZeroByte(i) and not self._containsZeroByte(number-i): 226 return i 227 228 def _find(self, category, reg=None, srcdst='dst', badDst=[], badSrc=None, dontModify=None, srcEqDst=False, switchRegs=False ): 229 quali = 1 230 231 if reg and reg[0] != 'r': 232 return 233 while quali < RopChainSystemX86_64.MAX_QUALI: 234 for binary in self._binaries: 235 for gadget in self._gadgets[binary]: 236 237 if gadget.category[0] == category and gadget.category[1] == quali: 238 239 if badSrc and (gadget.category[2]['src'] in badSrc \ 240 or gadget.affected_regs.intersection(badSrc)): 241 continue 242 if badDst and (gadget.category[2]['dst'] in badDst \ 243 or gadget.affected_regs.intersection(badDst)): 244 continue 245 if not gadget.lines[len(gadget.lines)-1][1].strip().endswith('ret') or 'esp' in gadget.simpleString() or 'rsp' in gadget.simpleString(): 246 continue 247 if srcEqDst and (not (gadget.category[2]['dst'] == gadget.category[2]['src'])): 248 continue 249 elif not srcEqDst and 'src' in gadget.category[2] and (gadget.category[2]['dst'] == gadget.category[2]['src']): 250 continue 251 if self._isModifiedOrDereferencedAccess(gadget, dontModify): 252 continue 253 if reg: 254 if gadget.category[2][srcdst] == reg: 255 self._updateUsedBinaries(gadget) 256 return gadget 257 elif switchRegs: 258 other = 'src' if srcdst == 'dst' else 'dst' 259 if gadget.category[2][other] == reg: 260 self._updateUsedBinaries(gadget) 261 return gadget 262 else: 263 self._updateUsedBinaries(gadget) 264 return gadget 265 266 quali += 1 267 268 269 def _createWriteStringWhere(self, what, where, reg=None, dontModify=[], idx=0): 270 badRegs = [] 271 badDst = [] 272 while True: 273 popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs, dontModify=dontModify) 274 if not popReg: 275 raise RopChainError('Cannot build writewhatwhere gadget!') 276 write4 = self._find(Category.WRITE_MEM, reg=popReg.category[2]['dst'], badDst= 277 badDst, srcdst='src') 278 if not write4: 279 badRegs.append(popReg.category[2]['dst']) 280 continue 281 else: 282 popReg2 = self._find(Category.LOAD_REG, reg=write4.category[2]['dst'], dontModify=[popReg.category[2]['dst']]+dontModify) 283 if not popReg2: 284 badDst.append(write4.category[2]['dst']) 285 continue 286 else: 287 break; 288 289 if len(what) % 8 > 0: 290 what += ' ' * (8 - len(what) % 8) 291 toReturn = '' 292 for index in range(0,len(what),8): 293 part = what[index:index+8] 294 295 toReturn += self._printRopInstruction(popReg,False) 296 toReturn += self._printAddString(part) 297 regs = self._paddingNeededFor(popReg) 298 for i in range(len(regs)): 299 toReturn +=self._printPaddingInstruction() 300 toReturn += self._printRopInstruction(popReg2, False) 301 302 toReturn += self._printRebasedAddress(toHex(where+index,8), idx=idx) 303 regs = self._paddingNeededFor(popReg2) 304 for i in range(len(regs)): 305 toReturn +=self._printPaddingInstruction() 306 toReturn += self._printRopInstruction(write4) 307 return (toReturn,popReg.category[2]['dst'], popReg2.category[2]['dst']) 308 309 310 def _createWriteRegValueWhere(self, what, where, dontModify=[], idx=0): 311 badRegs = [] 312 badDst = [] 313 while True: 314 315 316 write4 = self._find(Category.WRITE_MEM, reg=what, badDst=badDst, dontModify=dontModify, srcdst='src') 317 if not write4: 318 raise RopChainError('Cannot build writeregvaluewhere gadget!') 319 else: 320 popReg2 = self._find(Category.LOAD_REG, reg=write4.category[2]['dst'], dontModify=[what]+dontModify) 321 if not popReg2: 322 badDst.append(write4.category[2]['dst']) 323 continue 324 else: 325 break; 326 327 toReturn = self._printRopInstruction(popReg2, False) 328 toReturn += self._printRebasedAddress(toHex(where,8), idx=idx) 329 regs = self._paddingNeededFor(popReg2) 330 for i in range(len(regs)): 331 toReturn +=self._printPaddingInstruction() 332 toReturn += self._printRopInstruction(write4) 333 334 return (toReturn,what, popReg2.category[2]['dst']) 335 336 def _createLoadRegValueFrom(self, what, from_reg, dontModify=[], idx=0): 337 try: 338 return self._createLoadRegValueFromMov(what, from_reg, dontModify, idx) 339 except RopChainError: 340 return self._createLoadRegValueFromXchg(what, from_reg, dontModify, idx) 341 342 def _createLoadRegValueFromMov(self, what, from_reg, dontModify=[], idx=0): 343 badRegs = [] 344 badDst = [] 345 while True: 346 347 348 load4 = self._find(Category.LOAD_MEM, reg=what, badDst=badDst, dontModify=dontModify, srcdst='dst') 349 if not load4: 350 raise RopChainError('Cannot build loadwhere gadget!') 351 else: 352 popReg2 = self._find(Category.LOAD_REG, reg=load4.category[2]['src'], dontModify=[what,load4.category[2]['src']]+dontModify) 353 if not popReg2: 354 badDst.append(load4.category[2]['src']) 355 continue 356 else: 357 break; 358 359 toReturn = self._printRopInstruction(popReg2, False) 360 toReturn += self._printRebasedAddress(toHex(from_re,8), idx=idx) 361 regs = self._paddingNeededFor(popReg2) 362 for i in range(len(regs)): 363 toReturn +=self._printPaddingInstruction() 364 toReturn += self._printRopInstruction(load4) 365 366 return (toReturn,what, popReg2.category[2]['dst']) 367 368 def _createLoadRegValueFromXchg(self, what, from_reg, dontModify=[], idx=0): 369 badRegs = [] 370 badDst = [] 371 while True: 372 373 374 load4 = self._find(Category.XCHG_REG, reg=what, badDst=badDst, dontModify=dontModify, srcdst='src') 375 if not load4: 376 raise RopChainError('Cannot build loadwhere gadget!') 377 else: 378 mov = self._find(Category.LOAD_MEM, reg=load4.category[2]['dst'], badDst=badDst, dontModify=[load4.category[2]['dst']]+dontModify, srcdst='dst') 379 if not mov: 380 badDst.append(load4.category[2]['dst']) 381 continue 382 383 popReg2 = self._find(Category.LOAD_REG, reg=mov.category[2]['src'], dontModify=[what,load4.category[2]['src']]+dontModify) 384 if not popReg2: 385 badDst.append(load4.category[2]['src']) 386 continue 387 else: 388 break; 389 390 391 392 toReturn = self._printRopInstruction(popReg2, False) 393 toReturn += self._printRebasedAddress(toHex(from_reg,8), idx=idx) 394 regs = self._paddingNeededFor(popReg2) 395 for i in range(len(regs)): 396 toReturn +=self._printPaddingInstruction() 397 398 toReturn += self._printRopInstruction(mov) 399 400 toReturn += self._printRopInstruction(load4) 401 402 return (toReturn,what, popReg2.category[2]['dst']) 403 404 def _createNumberSubtract(self, number, reg=None, badRegs=None, dontModify=None): 405 if not badRegs: 406 badRegs=[] 407 while True: 408 sub = self._find(Category.SUB_REG, reg=reg, badDst=badRegs, badSrc=badRegs, dontModify=dontModify) 409 if not sub: 410 raise RopChainError('Cannot build number with subtract gadget for reg %s!' % reg) 411 popSrc = self._find(Category.LOAD_REG, reg=sub.category[2]['src'], dontModify=dontModify) 412 if not popSrc: 413 badRegs.append=[sub.category[2]['src']] 414 continue 415 popDst = self._find(Category.LOAD_REG, reg=sub.category[2]['dst'], dontModify=[sub.category[2]['src']]+dontModify) 416 if not popDst: 417 badRegs.append=[sub.category[2]['dst']] 418 continue 419 else: 420 break; 421 422 filler = self._createZeroByteFillerForSub(number) 423 424 toReturn = self._printRopInstruction(popSrc, False) 425 toReturn += self._printPaddingInstruction(toHex(filler,8)) 426 regs = self._paddingNeededFor(popSrc) 427 for i in range(len(regs)): 428 toReturn += self._printPaddingInstruction() 429 toReturn += self._printRopInstruction(popDst, False) 430 toReturn += self._printPaddingInstruction(toHex(filler+number,8)) 431 regs = self._paddingNeededFor(popDst) 432 for i in range(len(regs)): 433 toReturn += self._printPaddingInstruction() 434 toReturn += self._printRopInstruction(sub) 435 return (toReturn, popDst.category[2]['dst'],popSrc.category[2]['dst']) 436 437 def _createNumberAddition(self, number, reg=None, badRegs=None, dontModify=None): 438 if not badRegs: 439 badRegs=[] 440 while True: 441 sub = self._find(Category.ADD_REG, reg=reg, badDst=badRegs, badSrc=badRegs, dontModify=dontModify) 442 if not sub: 443 raise RopChainError('Cannot build number with addition gadget for reg %s!' % reg) 444 popSrc = self._find(Category.LOAD_REG, reg=sub.category[2]['src'], dontModify=dontModify) 445 if not popSrc: 446 badRegs.append=[sub.category[2]['src']] 447 continue 448 popDst = self._find(Category.LOAD_REG, reg=sub.category[2]['dst'], dontModify=[sub.category[2]['src']]+dontModify) 449 if not popDst: 450 badRegs.append(sub.category[2]['dst']) 451 continue 452 else: 453 break; 454 455 filler = self._createZeroByteFillerForAdd(number) 456 457 toReturn = self._printRopInstruction(popSrc, False) 458 toReturn += self._printPaddingInstruction(toHex(filler,8)) 459 regs = self._paddingNeededFor(popSrc) 460 for i in range(len(regs)): 461 toReturn += self._printPaddingInstruction() 462 toReturn += self._printRopInstruction(popDst, False) 463 toReturn += self._printPaddingInstruction(toHex(number - filler,8)) 464 regs = self._paddingNeededFor(popDst) 465 for i in range(len(regs)): 466 toReturn += self._printPaddingInstruction() 467 toReturn += self._printRopInstruction(sub) 468 469 return (toReturn, popDst.category[2]['dst'],popSrc.category[2]['dst']) 470 471 def _createNumberPop(self, number, reg=None, badRegs=None, dontModify=None): 472 if self._containsZeroByte(0xffffffff): 473 raise RopChainError("Cannot write value with pop -1 and inc gadgets, because there are badbytes in the negated number") 474 while True: 475 popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify) 476 if not popReg: 477 raise RopChainError('Cannot build number with xor gadget!') 478 incReg = self._find(Category.INC_REG, reg=popReg.category[2]['dst'], dontModify=dontModify) 479 if not incReg: 480 if not badRegs: 481 badRegs = [] 482 badRegs.append(popReg.category[2]['dst']) 483 else: 484 break 485 486 value = self._printPaddingInstruction(toHex(0xffffffff,8)) 487 toReturn = self._printRopInstruction(popReg, value=value) 488 for i in range(number+1): 489 toReturn += self._printRopInstruction(incReg) 490 491 return (toReturn ,popReg.category[2]['dst'],) 492 493 494 def _createNumberXOR(self, number, reg=None, badRegs=None, dontModify=None): 495 while True: 496 clearReg = self._find(Category.CLEAR_REG, reg=reg, badDst=badRegs, badSrc=badRegs,dontModify=dontModify, srcEqDst=True) 497 if not clearReg: 498 raise RopChainError('Cannot build number with xor gadget!') 499 if number > 0: 500 incReg = self._find(Category.INC_REG, reg=clearReg.category[2]['src'], dontModify=dontModify) 501 if not incReg: 502 if not badRegs: 503 badRegs = [] 504 badRegs.append(clearReg.category[2]['src']) 505 else: 506 break 507 else: 508 break 509 510 toReturn = self._printRopInstruction(clearReg) 511 for i in range(number): 512 toReturn += self._printRopInstruction(incReg) 513 514 return (toReturn, clearReg.category[2]['dst'],) 515 516 def _createNumberXchg(self, number, reg=None, badRegs=None, dontModify=None): 517 xchg = self._find(Category.XCHG_REG, reg=reg, badDst=badRegs, dontModify=dontModify) 518 if not xchg: 519 raise RopChainError('Cannot build number gadget with xchg!') 520 521 other = xchg.category[2]['src'] if xchg.category[2]['dst'] else xchg.category[2]['dst'] 522 523 toReturn = self._createNumber(number, other, badRegs, dontModify)[0] 524 525 toReturn += self._printRopInstruction(xchg) 526 return (toReturn, reg, other) 527 528 def _createNumberNeg(self, number, reg=None, badRegs=None, dontModify=None): 529 if number == 0: 530 raise RopChainError('Cannot build number gadget with neg if number is 0!') 531 if self._containsZeroByte((~number)+1): 532 raise RopChainError("Cannot use neg gadget, because there are badbytes in the negated number") 533 neg = self._find(Category.NEG_REG, reg=reg, badDst=badRegs, dontModify=dontModify) 534 if not neg: 535 raise RopChainError('Cannot build number gadget with neg!') 536 537 pop = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs, dontModify=dontModify) 538 if not pop: 539 raise RopChainError('Cannot build number gadget with neg!') 540 541 value = self._printPaddingInstruction(toHex((~number)+1, 8)) # two's complement 542 toReturn = self._printRopInstruction(pop, value=value) 543 toReturn += self._printRopInstruction(neg) 544 return (toReturn, reg,) 545 546 def _createNumber(self, number, reg=None, badRegs=None, dontModify=None, xchg=True): 547 try: 548 if self.containsBadbytes(number): 549 try: 550 return self._createNumberNeg(number, reg, badRegs,dontModify) 551 except RopChainError as e: 552 553 if number < 50: 554 try: 555 return self._createNumberXOR(number, reg, badRegs,dontModify) 556 except RopChainError: 557 try: 558 return self._createNumberPop(number, reg, badRegs,dontModify) 559 except RopChainError: 560 try: 561 return self._createNumberSubtract(number, reg, badRegs,dontModify) 562 except RopChainError: 563 return self._createNumberAddition(number, reg, badRegs,dontModify) 564 565 else : 566 try: 567 return self._createNumberSubtract(number, reg, badRegs,dontModify) 568 except RopChainError: 569 return self._createNumberAddition(number, reg, badRegs,dontModify) 570 else: 571 popReg =self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify) 572 if not popReg: 573 raise RopChainError('Cannot build number gadget!') 574 value = self._printPaddingInstruction(toHex(number,8)) 575 toReturn = self._printRopInstruction(popReg, value=value) 576 return (toReturn , popReg.category[2]['dst']) 577 except RopChainError: 578 return self._createNumberXchg(number, reg, badRegs, dontModify) 579 580 def _createAddress(self, address, reg=None, badRegs=None, dontModify=None): 581 popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify) 582 if not popReg: 583 raise RopChainError('Cannot build address gadget!') 584 585 toReturn = '' 586 587 toReturn += self._printRopInstruction(popReg,False) 588 toReturn += self._printRebasedAddress(toHex(address, 8), idx=self._usedBinaries.index((popReg.fileName, popReg.section))) 589 regs = self._paddingNeededFor(popReg) 590 for i in range(len(regs)): 591 toReturn +=self._printPaddingInstruction() 592 593 return (toReturn,popReg.category[2]['dst']) 594 595 def _createSyscall(self, reg=None, badRegs=None, dontModify=None): 596 syscall = self._find(Category.SYSCALL, reg=None, badDst=None, dontModify=dontModify) 597 if not syscall: 598 raise RopChainError('Cannot build syscall gadget!') 599 600 toReturn = '' 601 602 toReturn += self._printRopInstruction(syscall) 603 604 return (toReturn,) 605 606 def _createOpcode(self, opcode): 607 gadget = self._searchOpcode(opcode) 608 609 if gadget: 610 if (gadget.fileName, gadget.section) not in self._usedBinaries: 611 self._usedBinaries.append((gadget.fileName, gadget.section)) 612 return self._printRopInstruction(gadget) 613 614 615 def _searchOpcode(self, opcode): 616 r = Ropper() 617 gadgets = [] 618 for section in self._binaries[0].executableSections: 619 vaddr = section.virtualAddress 620 gadgets.extend(r.searchOpcode(self._binaries[0],opcode=opcode,disass=True)) 621 622 if len(gadgets) > 0: 623 return gadgets[0] 624 else: 625 raise RopChainError('Cannot create gadget for opcode: %s' % opcode) 626 627 def create(self): 628 pass 629 630 631class RopChainSystemX86_64(RopChainX86_64): 632 633 @classmethod 634 def usableTypes(self): 635 return (ELF, Raw) 636 637 @classmethod 638 def name(cls): 639 return 'execve' 640 641 def _createCommand(self, what, where, reg=None, dontModify=[], idx=0): 642 if len(what) % 8 > 0: 643 what = '/' * (8 - len(what) % 8) + what 644 return self._createWriteStringWhere(what,where, idx=idx) 645 646 def create(self, options): 647 cmd = options.get('cmd') 648 address = options.get('address') 649 if not cmd: 650 cmd = '/bin/sh' 651 if len(cmd.split(' ')) > 1: 652 raise RopChainError('No argument support for execve commands') 653 654 self._printMessage('ROPchain Generator for syscall execve:\n') 655 self._printMessage('\nwrite command into data section\nrax 0xb\nrdi address to cmd\nrsi address to null\nrdx address to null\n') 656 chain = self._printHeader() 657 gadgets = [] 658 can_create_command = False 659 chain_tmp = '\n' 660 if address is None: 661 section = self._binaries[0].getSection('.data') 662 663 length = math.ceil(float(len(cmd))/8) * 8 664 nulladdress = section.offset+length 665 try: 666 cmdaddress = section.offset 667 chain_tmp += self._createCommand(cmd,cmdaddress)[0] 668 can_create_command = True 669 670 except RopChainError as e: 671 self._printMessage('Cannot create gadget: writewhatwhere') 672 self._printMessage('Use 0x4141414141414141 as command address. Please replace that value.') 673 cmdaddress = 0x4141414141414141 674 if can_create_command: 675 badregs = [] 676 tmpx = '' 677 while True: 678 679 ret = self._createNumber(0x0, badRegs=badregs) 680 tmpx = ret[0] 681 try: 682 tmpx += self._createWriteRegValueWhere(ret[1], nulladdress)[0] 683 break 684 except BaseException as e: 685 #raise e 686 badregs.append(ret[1]) 687 688 chain_tmp += tmpx 689 gadgets.append((self._createAddress, [cmdaddress],{'reg':'rdi'},['rdi','edi', 'di'])) 690 gadgets.append((self._createAddress, [nulladdress],{'reg':'rsi'},['rsi','esi', 'si'])) 691 gadgets.append((self._createAddress, [nulladdress],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh'])) 692 gadgets.append((self._createNumber, [59],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah'])) 693 if address is not None and not can_create_command: 694 if type(address) is str: 695 cmdaddress = int(address, 16) 696 nulladdress = options.get('nulladdress') 697 if nulladdress is None: 698 self._printMessage('No address to a null bytes was given, 0x4242424242424242 is used instead.') 699 self._printMessage('Please replace that value.') 700 nulladdress = 0x4242424242424242 701 elif type(nulladdress) is str: 702 nulladdress = int(nulladdress,16) 703 704 gadgets.append((self._createNumber, [cmdaddress],{'reg':'rdi'},['rdi','edi', 'di'])) 705 gadgets.append((self._createNumber, [nulladdress],{'reg':'rsi'},['rsi','esi', 'si'])) 706 gadgets.append((self._createNumber, [nulladdress],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh'])) 707 gadgets.append((self._createNumber, [59],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah'])) 708 709 self._printMessage('Try to create chain which fills registers without delete content of previous filled registers') 710 chain_tmp += self._createDependenceChain(gadgets) 711 712 try: 713 self._printMessage('Look for syscall gadget') 714 chain_tmp += self._createSyscall()[0] 715 self._printMessage('syscall gadget found') 716 717 except RopChainError: 718 try: 719 self._printMessage('No syscall gadget found!') 720 self._printMessage('Look for syscall opcode') 721 722 chain_tmp += self._createOpcode('0f05') 723 self._printMessage('syscall opcode found') 724 725 except RopChainError: 726 chain_tmp += '# INSERT SYSCALL GADGET HERE\n' 727 self._printMessage('syscall opcode not found') 728 729 730 chain += self._printRebase() 731 chain += 'rop = \'\'\n' 732 733 chain += chain_tmp 734 chain += 'print rop' 735 return chain 736 737 738class RopChainMprotectX86_64(RopChainX86_64): 739 """ 740 Builds a ropchain for mprotect syscall 741 rax 0x7b 742 rdi address 743 rsi size 744 rdx 0x7 -> RWE 745 """ 746 747 @classmethod 748 def usableTypes(self): 749 return (ELF, Raw) 750 751 @classmethod 752 def name(cls): 753 return 'mprotect' 754 755 def _createJmp(self, reg=['rsp']): 756 r = Ropper() 757 gadgets = [] 758 for section in self._binaries[0].executableSections: 759 vaddr = section.virtualAddress 760 gadgets.extend(r.searchJmpReg(self._binaries[0],reg)) 761 762 763 764 if len(gadgets) > 0: 765 if (gadgets[0].fileName, gadgets[0].section) not in self._usedBinaries: 766 self._usedBinaries.append((gadgets[0].fileName, gadgets[0].section)) 767 return self._printRopInstruction(gadgets[0]) 768 else: 769 return None 770 771 def __extract(self, param): 772 if not match('0x[0-9a-fA-F]{1,16},0x[0-9a-fA-F]+', param) or not match('0x[0-9a-fA-F]{1,16},[0-9]+', param): 773 raise RopChainError('Parameter have to have the following format: <hexnumber>,<hexnumber> or <hexnumber>,<number>') 774 775 split = param.split(',') 776 if isHex(split[1]): 777 return (int(split[0], 16), int(split[1], 16)) 778 else: 779 return (int(split[0], 16), int(split[1], 10)) 780 781 782 def create(self, options={}): 783 address = options.get('address') 784 size = options.get('size') 785 if not address: 786 raise RopChainError('Missing parameter: address') 787 if not size: 788 raise RopChainError('Missing parameter: size') 789 790 if not match('0x[0-9a-fA-F]{1,8}', address): 791 raise RopChainError('Parameter address have to have the following format: <hexnumber>') 792 793 if not match('0x[0-9a-fA-F]+', size): 794 raise RopChainError('Parameter size have to have the following format: <hexnumber>') 795 796 address = int(address, 16) 797 size = int(size, 16) 798 799 self._printMessage('ROPchain Generator for syscall mprotect:\n') 800 self._printMessage('rax 0xa\nrdi address\nrsi size\nrdx 0x7 -> RWE\n') 801 802 chain = self._printHeader() 803 804 chain += 'shellcode = \'\\xcc\'*100\n\n' 805 806 gadgets = [] 807 gadgets.append((self._createNumber, [address],{'reg':'rdi'},['rdi','edi', 'di'])) 808 gadgets.append((self._createNumber, [size],{'reg':'rsi'},['rsi','esi', 'si'])) 809 gadgets.append((self._createNumber, [0x7],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh'])) 810 gadgets.append((self._createNumber, [0xa],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah'])) 811 812 self._printMessage('Try to create chain which fills registers without delete content of previous filled registers') 813 chain_tmp = '' 814 chain_tmp += self._createDependenceChain(gadgets) 815 try: 816 self._printMessage('Look for syscall gadget') 817 chain_tmp += self._createSyscall()[0] 818 self._printMessage('syscall gadget found') 819 except RopChainError: 820 chain_tmp += '\n# ADD HERE SYSCALL GADGET\n\n' 821 self._printMessage('No syscall gadget found!') 822 823 self._printMessage('Look for jmp esp') 824 jmp_esp = self._createJmp() 825 if jmp_esp: 826 self._printMessage('jmp esp found') 827 chain_tmp += jmp_esp 828 else: 829 self._printMessage('no jmp esp found') 830 chain_tmp += '\n# ADD HERE JMP ESP\n\n' 831 832 chain += self._printRebase() 833 chain += '\nrop = \'\'\n' 834 chain += chain_tmp 835 chain += 'rop += shellcode\n\n' 836 chain += 'print(rop)\n' 837 838 return chain 839