3

This is actually a ctf game: Enigma 2017 practice at hackcenter.com We have to recover a deleted file on ext3. I am following this tutorial.

The inode is 1036. istat gives Group 0

fsstat undelete.img
Group: 0:
  Inode Range: 1 - 1280
  ...
  Inode Table: 24 - 183
  ...

From here the node table has a size of 160 blocks, each block has 8 inodes. Inode 1036 is in block 153 and is the 4th entry.

This is confirmed by

debugfs -R 'imap <1036>' undelete.img 
debugfs 1.43.4 (31-Jan-2017)
Inode 1036 is part of block group 0
    located at block 153, offset 0x0180

jls undelete.img | grep 153$
46: Unallocated FS Block 2153
206:    Unallocated FS Block 153
214:    Unallocated FS Block 153
224:    Unallocated FS Block 153
680:    Unallocated FS Block 4153


jcat undelete.img 8 206 | dd bs=128 skip=3 count=1 | xxd
1+0 records in
1+0 records out
00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
128 bytes copied, 0,00719467 s, 17,8 kB/s


jcat undelete.img 8 214 | dd bs=128 skip=3 count=1 | xxd
1+0 records in
1+0 records out
00000000: a481 0000 2000 0000 4d70 8b58 4d70 8b58  .... ...Mp.XMp.X
00000010: 4d70 8b58 0000 0000 0000 0100 0200 0000  Mp.X............
00000020: 0000 0000 0100 0000 ef08 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 17ea 60e7 0000 0000 0000 0000  ......`.........
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
128 bytes copied, 0,00714798 s, 17,9 kB/s


jcat undelete.img 8 224 | dd bs=128 skip=3 count=1 | xxd
1+0 records in
1+0 records out
00000000: a481 0000 0000 0000 4d70 8b58 4d70 8b58  ........Mp.XMp.X
00000010: 4d70 8b58 4d70 8b58 0000 0000 0000 0000  Mp.XMp.X........
00000020: 0000 0000 0100 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 17ea 60e7 0000 0000 0000 0000  ......`.........
128 bytes copied, 0,00556548 s, 23,0 kB/s
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

The only direct block pointer I got is 0x8ef at offset 40. The block size was reported by fsstat. But

dd bs=1024 skip=2287 count=1 if=undelete.img | xxd

gives only zeros.

I do not know what is wrong.

1 Answer 1

1
+100

You conveniently forgot to mention the URL of the filesystem image, but after registering on hackcenter.com it wasn't that hard to find. (I'm not going to repeat the URL here).

Instead of blindly following a recipe, let's look at the image and figure out what happens. fls shows that there's lots of files named filler-0, filler-1 etc. until filler-1023, then there's a file key and that has been deleted.

Looking for commits

jls undelete.img | grep Commit
...
228:    Unallocated Commit Block (seq: 9, sec: 1485533263.2387673088)
...

finds that 9 is the last commit. Let's look at what happens before that commit (I've annoted the block numbers)

205:    Unallocated FS Block 3112
206:    Unallocated FS Block 153   # our inode
207:    Unallocated FS Block 3113  # data
208:    Unallocated FS Block 3114  # data
209:    Unallocated FS Block 3115  # data
210:    Unallocated Commit Block (seq: 7, sec: 1485533262.1970733056)
211:    Unallocated Descriptor Block (seq: 8)
212:    Unallocated FS Block 23    # inode bitmap
213:    Unallocated FS Block 2     # group desc
214:    Unallocated FS Block 153   # our inode blk
215:    Unallocated FS Block 24    # first inode blk
216:    Unallocated FS Block 5118
217:    Unallocated FS Block 22    # data bitmap
218:    Unallocated FS Block 3116  # data
219:    Unallocated Commit Block (seq: 8, sec: 1485533262.2227109888)
220:    Unallocated Descriptor Block (seq: 9)
221:    Unallocated FS Block 5118
222:    Unallocated FS Block 24    # first inode blk
223:    Unallocated FS Block 1     # super blk
224:    Unallocated FS Block 153   # our inode blk
225:    Unallocated FS Block 22    # data bitmap
226:    Unallocated FS Block 2     # group desc
227:    Unallocated FS Block 23    # inode bitmap
228:    Unallocated Commit Block (seq: 9, sec: 1485533263.2387673088)
229:    Unallocated FS Block Unknown

So in commit #7, our inode block and three data blocks were written. In commit #8, some allocation and touching of inode is going on and a single data block is written. In commit #9, it's nearly the same, but no data block is written.

So the guess is that in commit #7, we see the last of our filler files being created, in commit #8, key is created and written, and in commit #9, it's deleted again.

Now let's look at the copies of inode block 153 in the journal. 224 (inode after deletion) and 206 (inode before creation) have an empty direct block pointer list. I don't know what happened when you looked at 214, but I do get:

$ jcat undelete.img 8 214 | dd bs=128 skip=3 count=1 | xxd
00000000: a481 0000 2000 0000 4e70 8b58 4e70 8b58  .... ...Np.XNp.X
00000010: 4e70 8b58 0000 0000 0000 0100 0200 0000  Np.X............
00000020: 0000 0000 0100 0000 2c0c 0000 0000 0000  ........,.......
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 8682 a674 0000 0000 0000 0000  .......t........
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

So in the direct block list at 0x28, we have one block at 0x0c2c or 3116, as guessed before.

Let's verify that we are not off by looking at some contents:

$ fcat filler-1022 undelete.img 
f1755813fae6d0f542f962f50ff37184
$ dd if=undelete.img bs=1024 skip=3114 count=1 2> /dev/null ; echo
f1755813fae6d0f542f962f50ff37184

$ fcat filler-1023 undelete.img 
aa08cba3462555833ffed443474bd133
$ dd if=undelete.img bs=1024 skip=3115 count=1 2> /dev/null ; echo
aa08cba3462555833ffed443474bd133

Yes, that's the data in filler written, as guessed. So what's in block 3116? Turns out to be only zeroes, which means that block never was updated. But we do have copies in the journal. In case of our two filler files:

$ jcat undelete.img 208
f1755813fae6d0f542f962f50ff37184

$ jcat undelete.img 209
aa08cba3462555833ffed443474bd133

And now finding the key should be easy (I won't do it publicly, for obvious reasons).

2
  • I downloaded the file again, but at 214 I got what I have posted before (copy pasted your command). This is strange, because the last commit is still 228. Are the copies you are referring at 206, 214 and 224? Because at 206 and 224 I got no direct pointers. I also created a similar sized image manually, and there worked everything.
    – robert
    Jun 20, 2017 at 4:13
  • To quote: "224 (inode after deletion) and 206 (inode before creation) have an empty direct block pointer list". So yes, they are at 206, 214, 224; the first and last have no direct pointers (as you said) for the reason given, and I've no idea why your content of 214 is garbled, and it doesn't really matter if it's garbled, because you can just look at the commit log - you can recover the key without knowing the contents of 214.
    – dirkt
    Jun 20, 2017 at 6:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .