Пожалуйста, обратите внимание, что пользователь заблокирован
cert9.db - впервые вижу, шо це зе?(key3.db/key4.db, cert9.db/cert9.db)
Скрытое содержимое
cert9.db - впервые вижу, шо це зе?(key3.db/key4.db, cert9.db/cert9.db)
Скрытое содержимое
Файлик из профиля лисы.cert9.db - впервые вижу, шо це зе?
зачем cert9.db. вродь ключи из key3.db, key4 хватит же чтоб дешифровать logins.json and signos.sqlite?Файлик из профиля лисы.
Забыл там ещё NSS_Shutdown вызвать по окончанию работы с профилем, поправлю чуть позже.
Этот код, скорее всего, не будет у вас работать. Позже выложу фукс-версию.Переписал на golang. Собирать нужно с cgo.
./profile - папка с профилем (key3.db/key4.db, cert8.db/cert9.db)
./libs - папка с либами фаерфокса
Скрытое содержимое
А что там не так?Этот код, скорее всего, не будет у вас работать. Позже выложу фукс-версию.
Tested on ubuntu 20.04, debian 10, ubuntu 16.04, opensuse.Переписал на golang. Собирать нужно с cgo.
./profile - папка с профилем (key3.db/key4.db, cert8.db/cert9.db)
./libs - папка с либами фаерфокса
Скрытое содержимое
package main
/*
#include <stdlib.h>
typedef struct {
unsigned int type;
unsigned char* data;
size_t len;
} SECItem;
*/
import "C"
import (
"encoding/base64"
"errors"
"fmt"
"log"
"os"
"unsafe"
"github.com/rainycape/dl"
)
type Nss struct {
NSS_Init func(string) int
NSS_Shutdown func()
PK11_GetInternalKeySlot func() uintptr
PK11_FreeSlot func(uintptr)
PK11_CheckUserPassword func(uintptr, string) int
PK11_Authenticate func(uintptr, int, uintptr) int
PK11SDR_Decrypt func(*C.SECItem, *C.SECItem, uintptr) int
SECITEM_ZfreeItem func(*C.SECItem, int)
PORT_GetError func() int
PR_ErrorToName func(int) *C.char
PR_ErrorToString func(int, uint32) *C.char
}
func GetFunc(libnss3 *dl.DL) (nss Nss, _ error) {
if err := libnss3.Sym("NSS_Init", &nss.NSS_Init); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("NSS_Shutdown", &nss.NSS_Shutdown); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PK11_GetInternalKeySlot", &nss.PK11_GetInternalKeySlot); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PK11_CheckUserPassword", &nss.PK11_CheckUserPassword); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PK11_Authenticate", &nss.PK11_Authenticate); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PK11SDR_Decrypt", &nss.PK11SDR_Decrypt); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PORT_GetError", &nss.PORT_GetError); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PR_ErrorToName", &nss.PR_ErrorToName); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PR_ErrorToString", &nss.PR_ErrorToString); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("PK11_FreeSlot", &nss.PK11_FreeSlot); err != nil {
return Nss{}, err
}
if err := libnss3.Sym("SECITEM_ZfreeItem", &nss.SECITEM_ZfreeItem); err != nil {
return Nss{}, err
}
return nss, nil
}
func (nss Nss) Error() string {
err := nss.PORT_GetError()
return C.GoString(nss.PR_ErrorToName(err)) + "(" + C.GoString(nss.PR_ErrorToString(err, 0)) + ")"
}
func InitNSS(nss Nss, path string) error {
if status := nss.NSS_Init(path); status != 0 {
return errors.New("NSS_Init(\"" + path + "\") error: " + nss.Error())
}
slot := nss.PK11_GetInternalKeySlot()
if slot == 0 {
nss.NSS_Shutdown()
return errors.New("PK11_GetInternalKeySlot() error: " + nss.Error())
}
if status := nss.PK11_CheckUserPassword(slot, ""); status != 0 {
nss.NSS_Shutdown()
nss.PK11_FreeSlot(slot)
return errors.New("PK11_CheckUserPassword() error: " + nss.Error())
}
if status := nss.PK11_Authenticate(slot, 1, 0); status != 0 {
nss.NSS_Shutdown()
nss.PK11_FreeSlot(slot)
return errors.New("PK11_Authenticate() error: " + nss.Error())
}
nss.PK11_FreeSlot(slot)
return nil
}
func Decrypt(encData string) (string, error) {
libnss3, err := dl.Open("libnss3.so", 0)
if err != nil {
return "", err
}
defer libnss3.Close()
nss, err := GetFunc(libnss3)
if err != nil {
return "", err
}
if err := InitNSS(nss, "sql:profile"); err != nil {
return "", err
}
defer nss.NSS_Shutdown()
data, err := base64.StdEncoding.DecodeString(encData)
if err != nil {
return "", err
}
in := (*C.SECItem)(C.malloc(C.sizeof_SECItem))
in.data = (*C.uchar)(&data[0])
in.len = (C.ulong)(len(data))
defer C.free(unsafe.Pointer(in))
out := (*C.SECItem)(C.malloc(C.sizeof_SECItem))
defer C.free(unsafe.Pointer(out))
if status := nss.PK11SDR_Decrypt(in, out, 0); status != 0 {
return "", errors.New("PK11SDR_Decrypt() error: " + nss.Error())
}
bytes := C.GoBytes(unsafe.Pointer(out.data), C.int(out.len))
return string(bytes), nil
}
func main() {
dec, err := Decrypt("enc_data")
if err != nil {
log.Fatal(err)
}
fmt.Println(dec)
}
UPD1: лучше не юзать github.com/rainycape/dl, кидает паникиTested on ubuntu 20.04, debian 10, ubuntu 16.04, opensuse.
./profile - firefox profile (key3.db/key4.db, cert8.db/cert9.db)
Скрытое содержимое
UPD: Не забудьте установить либы nss3: sudo apt install libnss3
package gecko
/*
#include <stdlib.h>
typedef struct {
unsigned int type;
unsigned char* data;
size_t len;
} SECItem;
int one = 1;
int NSS_Init(const char*);
int NSS_Shutdown(void);
void* PK11_GetInternalKeySlot(void);
void PK11_FreeSlot(void*);
int PK11_CheckUserPassword(void*, char*);
int PK11_Authenticate(void*, int, void*);
int PK11SDR_Decrypt(SECItem*, SECItem*, void*);
void SECITEM_ZfreeItem(SECItem*, int);
int PORT_GetError();
char* PR_ErrorToName(int);
#cgo LDFLAGS: -lnss3 -lnspr4
*/
import "C"
import (
"encoding/base64"
"errors"
"unsafe"
)
func nssError() string {
err := C.PORT_GetError()
return C.GoString(C.PR_ErrorToName(err))
}
func initNSS(path string) error {
cPath := C.CString(path)
defer C.free(unsafe.Pointer(cPath))
if status := C.NSS_Init(cPath); status != 0 {
return errors.New("NSS_Init(\"" + path + "\") error: " + nssError())
}
slot := C.PK11_GetInternalKeySlot()
if slot == nil {
C.NSS_Shutdown()
return errors.New("PK11_GetInternalKeySlot() error: " + nssError())
}
cEmptyStr := C.CString("")
defer C.free(unsafe.Pointer(cEmptyStr))
if status := C.PK11_CheckUserPassword(slot, cEmptyStr); status != 0 {
C.NSS_Shutdown()
C.PK11_FreeSlot(slot)
return errors.New("PK11_CheckUserPassword() error: " + nssError())
}
if status := C.PK11_Authenticate(slot, C.one, nil); status != 0 {
C.NSS_Shutdown()
C.PK11_FreeSlot(slot)
return errors.New("PK11_Authenticate() error: " + nssError())
}
C.PK11_FreeSlot(slot)
return nil
}
func Decrypt(profilePath, encData string) (string, error) {
if err := initNSS("sql:" + profilePath); err != nil {
return "", err
}
defer C.NSS_Shutdown()
data, err := base64.StdEncoding.DecodeString(encData)
if err != nil {
return "", err
}
in := (*C.SECItem)(C.malloc(C.sizeof_SECItem))
in.data = (*C.uchar)(&data[0])
in.len = (C.ulong)(len(data))
defer C.free(unsafe.Pointer(in))
out := (*C.SECItem)(C.malloc(C.sizeof_SECItem))
defer C.free(unsafe.Pointer(out))
if status := C.PK11SDR_Decrypt(in, out, nil); status != 0 {
return "", errors.New("PK11SDR_Decrypt() error: " + nssError())
}
bytes := C.GoBytes(unsafe.Pointer(out.data), C.int(out.len))
return string(bytes), nil
}
Haunt будет против, нахера делать наплыв кидсов с суперприват решениями по фф)если Haunt не будет против
Кстати да, забыл. Поправлю. Спасибо, что заметил.А чего PK11_FreeSlot в defer не загнал?
Если мне память не изменяет - нет.И странно, в Го нет возможности сишные структуры на стеке/в гц выделить?
Мне вообще не очень нравится, как в го реализован CGO. В том же питоне немного удобнее работать с си.Маллочить структуру размеров в 20 байт - это что-то из серии дотнета уже, а никак не нативного языка программирования.
Да, ЦГо выглядит ппц каким костылем. Я обычно вспоминаю об этом, когда меня спрашивают, почему я не перевариваю Го. Ну вспоминаю само собой после обработки ошибок и отсутствия генериков)). Посмотрим, что там будет в Го 2.0, но я все равно скептически настроен.Мне вообще не очень нравится, как в го реализован CGO. В том же питоне немного удобнее работать с си.
Да поробуй, прекрасный язык, на самом делеДа, ЦГо выглядит ппц каким костылем. Я обычно вспоминаю об этом, когда меня спрашивают, почему я не перевариваю Го. Ну вспоминаю само собой после обработки ошибок и отсутствия генериков)). Посмотрим, что там будет в Го 2.0, но я все равно скептически настроен.
Я пробовал когда то давно, разочаровался и забил. Да и сейчас у меня нет в нем никакой необходимости. Среди нативных компиляторов есть те, которые мне нравятся куда больше (там всякие Nim, Zig, D и тд), бекенд для веб сервисов вполне можно клепать на Python или Kotlin или Elixir, а для мобилок он пока не пригоден и не понятно, будет ли пригоден хоть когда-то. Ну просто у меня нет какой-то ниши, в которую можно было бы Гофера впихнить.Да поробуй, прекрасный язык, на самом деле
Подниму тему. Недавно разбирался с этим всем, тоже пришел к выводу что лучше серверная реализация (в отличие от хрома, фф требует уж слишком много кода, за который может уцепится авер, да и в целом сложнее). Но РНР не умеет подгружать либы, а каких-то врапперов , в отличии от openssl, для nss на нем нет. Поэтому все же остановился на кастомной серверной реализации (тупо переписал lazagne на PHP). Хз касаемо подводных камней, разве что реально, как ты говорил, поменяют реализацию.У нас есть грубо 4 способа.
-nss тащим на клиент.
-Кастомная реализация на клиенте
-nss на сервере
-Кастомная реализация на сервере.
>>> Но РНР не умеет подгружать либыПодниму тему. Недавно разбирался с этим всем, тоже пришел к выводу что лучше серверная реализация (в отличие от хрома, фф требует уж слишком много кода, за который может уцепится авер, да и в целом сложнее). Но РНР не умеет подгружать либы, а каких-то врапперов , в отличии от openssl, для nss на нем нет. Поэтому все же остановился на кастомной серверной реализации (тупо переписал lazagne на PHP). Хз касаемо подводных камней, разве что реально, как ты говорил, поменяют реализацию.
кстати, интересно, зачем они ее меняют и зачем так заморочено все зашифровано? Какой смысл шифровать эти профили, если один фиг, если у малвары есть доступ к профилю, все можно раздешить. Это же опенсорц. Яндекс шифрует, но у них код закрытый, там логично, а тут хз.
А как на серве грузить мне интересно? Вы что ядро вин тоже на серв вынесете? В дллках лисы я смотрел в импорте, там импорты win библиотек, даже в некоторых dll я видел вызовы LoadLibraryExW, а для этого ядро надобно.Подниму тему. Недавно разбирался с этим всем, тоже пришел к выводу что лучше серверная реализация (в отличие от хрома, фф требует уж слишком много кода, за который может уцепится авер, да и в целом сложнее). Но РНР не умеет подгружать либы, а каких-то врапперов , в отличии от openssl, для nss на нем нет. Поэтому все же остановился на кастомной серверной реализации (тупо переписал lazagne на PHP). Хз касаемо подводных камней, разве что реально, как ты говорил, поменяют реализацию.
кстати, интересно, зачем они ее меняют и зачем так заморочено все зашифровано? Какой смысл шифровать эти профили, если один фиг, если у малвары есть доступ к профилю, все можно раздешить. Это же опенсорц. Яндекс шифрует, но у них код закрытый, там логично, а тут хз.
Какое ядро? Если сервер крутится на винде, ты можешь работать с апи винды.А как на серве грузить мне интересно? Вы что ядро вин тоже на серв вынесете? В дллках лисы я смотрел в импорте, там импорты win библиотек, даже в некоторых dll я видел вызовы LoadLibraryExW, а для этого ядро надобно.
Я через heavens gate гружу x64 dll лисы. Эти либы лисы тянут за собой crt и STL. Некоторые вызовы winapi(после переключения в x64) хуево отрабатывают и крашат. Все это я пофиксил, но если честно такой костыль получился, что просто нет слов