<aside> 🦸🏻 Автор: Дима Богер, [email protected]

</aside>

Part 1

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/017f509a-7b8d-4030-9bd9-648087b50eac/Untitled.png

На входе в задачу — ссылка на сайт в облаке, принципиальная схема приложения и слухи про утечки в голанге. Причем и слухи об утечке, и схему приложения прикрепили уже позже.

Две виртуалки в облаке: одна обслуживает запросы к админке, а другая к публичной версии сайта. Админка за Google IAP, поговорим про это чуть дальше.

Две виртуалки в облаке: одна обслуживает запросы к админке, а другая к публичной версии сайта. Админка за Google IAP, поговорим про это чуть дальше.

Подсказок негусто, поэтому начинаем копаться в сайте и хосте. Сайт довольно простой, и состоит из одного SPA приложения, загружаемого из /. Пройдёмся по всему что там есть:

Форма ввода, отправляющая PUT /api/order , возвращающая ID заказа нашей еды.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/fe51b9ef-3956-42b7-a3c6-f7cb2c7facf6/Untitled.png

Запрос на создание ордера и его ответ

Запрос на создание ордера и его ответ

Параллельно запускаем набор волшебника из dirsearch (ищет открытые URL сайта с чем-нибудь интересным) и nmap (сканирует порты). Сверху на сайте есть вкладка admin, и она ведёт себя очень интересно:

Т.к. мы можем спокойно почитать исходники всего SPA, то посмотрим что вообще делает закрытая часть приложения:

t.prototype.componentDidMount = function() {
    p.default.dev || window.location.host === p.default.adminIap || window.location.replace("https://" + p.default.adminIap + "/");  // REDIRECT GUARD
}
3051: function(e, t, n) {
    ... // ADMIN API
    t.putOrder = function(e, t) {
        return fetch("/api/order", {
            method: "PUT",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({
                address: e,
                phone: t
            })
        })
    }
    ,
    t.getOrders = function() {
        var e = o.default.dev ? {
            headers: {
                "x-dev-email": o.default.email
            }
        } : {};
        return fetch("/api/admin/orders", e)
    }
    ,
    t.getUsers = function() {
        var e = o.default.dev ? {
            headers: {
                "x-dev-email": o.default.email
            }
        } : {};
        return fetch("/api/admin/users", e)
    }
    ,
    t.getFiles = function() {
        var e = o.default.dev ? {
            headers: {
                "x-dev-email": o.default.email
            }
        } : {};
        return fetch("/api/admin/files", e)
    }
    ,
    t.getMe = function() {
        var e = o.default.dev ? {
            headers: {
                "x-dev-email": o.default.email
            }
        } : {};
        return fetch("/api/admin/me", e)
    }
},
3329: (e,t)=>{
    t.default = { // SPA CONFIG
        adminIap: "cloud-eats-admin.2537ly.space",
        dev: !1,
        email: "accounts.google.com:[email protected]"
    }
}

Что мы видим: