O próprio banco guarda a lista das suas tabelas e colunas, e a injeção pode lê-la.
Para roubar um dado, o atacante precisa saber onde ele está: em qual tabela, em qual coluna. Ele não precisa adivinhar. Todo banco mantém um catálogo com a descrição de si mesmo, e esse catálogo é uma tabela como qualquer outra, que a injeção lê do mesmo jeito.
No SQLite o catálogo é sqlite_master, com uma linha por tabela, incluindo o CREATE TABLE que lista as colunas. No MySQL e no PostgreSQL é o conjunto information_schema (information_schema.tables, information_schema.columns). Com um UNION, o atacante faz:
listar as tabelas: UNION SELECT name FROM sqlite_master WHERE type='table';
ver as colunas de uma tabela: ler o sql dela no sqlite_master, ou information_schema.columns;
então extrair o dado da tabela e coluna descobertas.
Por isso esconder nomes de tabela não protege: o banco entrega o mapa. A proteção é fechar a injeção na origem, com consulta parametrizada.
O UNION lê o catálogo sqlite_master e recebe os nomes das tabelas e as colunas de cada uma, o mapa que leva até a tabela do segredo.