| Bellacosa Mainframe e o perigo de softwares esquecidos |
☕ UM CAFÉ NO BELLACOSA MAINFRAME
🔑 NOIR STARGA E A DUNGEON DOS PRIVILÉGIOS — QUANDO O PROGRAMADOR COBOL DESCOBRIU QUE O PROGRAMA ESQUECIDO PODIA SER MAIS PERIGOSO QUE O ADMINISTRADOR
RACF, SPECIAL, SURROGAT, started tasks, APF, service accounts, Db2 packages, CICS, COBOL, JCL, SMF, privilege paths, grafos de segurança — e o dia em que Noir Starga descobriu uma dungeon que ninguém visitava havia vinte anos.
🎬 PRÓLOGO — A PORTA QUE NINGUÉM LEMBRAVA
Noir Starga estava parado diante de uma porta.
Não era particularmente impressionante.
Não havia dragões.
Não havia demônios.
Não havia sequer uma placa dizendo:
PERIGO.
Na verdade, havia apenas quatro caracteres:
PAY9— O que é isso? — perguntou Noir.
O programador COBOL olhou para a tela verde.
— Uma transação CICS.
— O que ela faz?
Silêncio.
— Quem usa?
Mais silêncio.
— Quando foi criada?
O COBOLzeiro consultou alguns registros.
— Parece que em 1999.
Noir sorriu.
— Excelente. Vamos entrar.
— Mas ninguém usa isso há anos!
Noir colocou a mão sobre a porta.
— Exatamente por isso vamos entrar.
Bem-vindo à dungeon dos privilégios esquecidos.
🧠 CAPÍTULO 1 — PRIMEIRO: O QUE DIABOS É PRIVILÉGIO?
Quando começamos a estudar segurança de mainframe, nosso modelo mental costuma ser simples.
Temos um usuário:
USER01Temos um recurso:
BANK.CUSTOMER.MASTERE perguntamos:
USER01 pode acessar BANK.CUSTOMER.MASTER?Talvez o RACF responda:
READou:
UPDATEou simplesmente:
NONEParece simples.
Só que sistemas corporativos reais não funcionam apenas através de relações diretas entre usuários e arquivos.
Noir desenhou no quadro:
USER
|
v
RESOURCE— Isso — explicou ele — é apenas a entrada da dungeon.
No mundo real podemos ter:
USER
|
v
CICS TRANSACTION
|
v
COBOL PROGRAM
|
v
DB2 PACKAGE
|
v
TABLEOu:
USER
|
v
SURROGAT
|
v
SERVICE ACCOUNT
|
v
JOB
|
v
PROGRAM
|
v
DATASETOu ainda:
USER
|
v
AUTOMATION
|
v
STARTED TASK
|
v
PRIVILEGED CODE
|
v
SYSTEM RESOURCEPercebeu a diferença?
A pergunta:
"O usuário possui acesso ao recurso?"
pode ser completamente diferente de:
"O usuário consegue provocar alguma coisa que possui acesso ao recurso?"
Esse será nosso primeiro princípio:
ACESSO DIRETO ≠ CAPACIDADE INDIRETA
👑 CAPÍTULO 2 — RACF SPECIAL: O CHEFÃO QUE TODO MUNDO CONHECE
Imagine entrar numa dungeon e encontrar um sujeito carregando uma espada de três metros, armadura dourada e uma placa:
BOSS FINALEsse é aproximadamente o problema do atributo SPECIAL.
No RACF, usuários com poderes administrativos elevados são obviamente importantes para segurança.
Quando alguém pergunta:
Quem possui privilégios perigosos?
é natural procurar imediatamente coisas como:
SPECIAL
OPERATIONS
AUDITORE devemos procurar.
Mas existe uma curiosidade.
Justamente porque esses privilégios são conhecidos, eles normalmente aparecem no radar.
Auditores perguntam por eles.
Administradores revisam.
Ferramentas de compliance procuram.
Relatórios listam.
Equipes IAM recertificam.
Portanto, um usuário com SPECIAL pode possuir enorme poder, mas é um poder visível.
Noir escreveu:
VISIBLE POWERe então perguntou:
— E o que acontece quando o poder não está no usuário?
É aí que nossa aventura começa de verdade.
🎭 CAPÍTULO 3 — SURROGAT: "EU NÃO POSSO, MAS ELE PODE"
Imagine:
USER01não possui acesso a:
PAYROLL.MASTERO auditor executa seu relatório:
USER01 -> PAYROLL.MASTERResultado:
NONEMissão cumprida?
Talvez não.
Suponha que exista uma identidade:
PAYSERVque realmente precise acessar recursos da folha de pagamento.
Agora imagine que USER01 tenha autorização para submeter determinados trabalhos utilizando PAYSERV como execution userid através dos controles de SURROGAT.
Nosso desenho passa a ser:
USER01
|
| SURROGAT
v
PAYSERV
|
| UPDATE
v
PAYROLL.MASTERVeja a pegadinha.
Pergunta:
USER01 tem UPDATE em PAYROLL.MASTER?Resposta:
NÃOMas outra pergunta:
USER01 consegue chegar a uma identidade
capaz de atualizar PAYROLL.MASTER?A resposta pode ser:
SIMNoir sorriu.
Encontramos nossa primeira passagem secreta.
Esse é exatamente o motivo pelo qual segurança moderna precisa pensar em caminhos, e não apenas em permissões individuais.
🤖 CAPÍTULO 4 — STARTED TASKS: USUÁRIOS QUE NÃO TOMAM CAFÉ
Um programador iniciante pode imaginar que toda identidade corresponde a uma pessoa.
Não corresponde.
No z/OS temos serviços executando continuamente:
CICS
DB2
MQ
TCPIP
SCHEDULER
MONITOR
BACKUP
AUTOMATIONMuitos deles executam como started tasks, ou STCs.
Essas tarefas precisam de identidades e autoridades adequadas às funções que realizam.
Isso cria um conceito importante:
uma identidade privilegiada não precisa possuir um teclado.
Ela pode ser software.
Considere:
STC01Ela executa automaticamente.
Agora imagine que essa STC leia parâmetros de:
SYS1.PARMLIBou outra biblioteca de configuração.
Talvez carregue módulos de uma load library.
Talvez leia scripts.
Talvez processe comandos.
Talvez consuma mensagens.
Nossa análise não pode terminar em:
STC01 possui autoridade?Precisamos continuar:
Quem controla STC01?Depois:
Quem controla aquilo que STC01 executa?E depois:
Quem controla aquilo que STC01 lê?A dungeon ganhou novos corredores.
☢️ CAPÍTULO 5 — APF: A SALA ONDE NOIR MANDOU NÃO TOCAR EM NADA
Chegamos agora a um assunto mais delicado.
APF — Authorized Program Facility.
Simplificando bastante para nosso COBOLzeiro iniciante: o z/OS precisa distinguir código comum de determinados códigos que participam de contextos privilegiados do sistema.
APF faz parte desse universo.
Por isso, bibliotecas autorizadas precisam receber enorme atenção.
Imagine:
SYS1.AUTHLIBcomo biblioteca relevante para execução autorizada.
A pergunta óbvia seria:
Quais programas estão nela?Boa pergunta.
Mas Noir aponta para outra porta:
Quem pode ALTERAR essa biblioteca?Aí o café fica frio.
Porque podemos ter:
USER
|
| UPDATE
v
APF LIBRARY
|
| contains
v
AUTHORIZED CODENão significa automaticamente que qualquer alteração resulte em comprometimento — o funcionamento real depende do contexto e das proteções existentes.
Mas a relação é importante demais para ser ignorada.
A investigação deve correlacionar:
APF configuration
+
dataset protection
+
UPDATE authority
+
groups
+
service accounts
+
deployment mechanismsEsse é um exemplo perfeito de controle indireto.
🦖 CAPÍTULO 6 — O COBOL DE 1998
Finalmente chegamos ao nosso dinossauro.
Imagine o programa:
PAY001Criado em 1998.
Ele contém algo parecido com:
EXEC SQL
UPDATE CUSTOMER
SET CREDIT_LIMIT = :WS-LIMIT
WHERE CUSTOMER_ID = :WS-CUSTOMER
END-EXEC.Na época, era parte importante do sistema.
Depois vieram:
PAY002
PAY003
PAYWEB
PAYAPI
PAYRESTEm 2026 ninguém fala sobre PAY001.
Mas alguém pergunta:
— Ele foi removido?
Silêncio.
— A transação que o chama foi removida?
Silêncio.
— O package Db2 desapareceu?
Silêncio.
— A autorização foi revogada?
Outro silêncio.
Noir abre a porta.
PAY001 IS STILL ALIVEBem-vindo ao privilégio fóssil.
O processo de negócio pode ter morrido.
A documentação pode ter desaparecido.
A equipe pode ter se aposentado.
Mas a capacidade técnica pode continuar funcionando.
🏦 CAPÍTULO 7 — DB2 PACKAGES E A AUTORIDADE QUE NÃO ESTÁ ONDE VOCÊ ESPERA
Para entender essa parte, nosso programador COBOL precisa aprender rapidamente como COBOL e Db2 convivem.
Podemos escrever:
EXEC SQL
SELECT NAME
INTO :WS-NAME
FROM CUSTOMER
WHERE CUSTOMER_ID = :WS-ID
END-EXEC.No processo tradicional de construção de aplicações Db2 entram conceitos como:
COBOL SOURCE
|
v
DBRM
|
v
BIND
|
v
PACKAGEO importante para nossa investigação é compreender que existe uma camada de autorização envolvendo execução de packages, planos, objetos e contexto de execução.
Portanto, perguntar apenas:
USER01 tem UPDATE na tabela?pode não representar toda a realidade operacional.
Talvez tenhamos:
USER01
|
| EXECUTE
v
APPLICATION
|
v
PACKAGE
|
v
DATABASE OBJECTO usuário utiliza uma capacidade disponibilizada pela aplicação.
Isso é absolutamente normal.
Aliás, é justamente assim que sistemas deveriam frequentemente funcionar: usuários não precisam receber acesso arbitrário aos objetos internos quando a aplicação pode oferecer operações controladas.
O problema começa quando esquecemos que aquela capacidade existe.
🏧 CAPÍTULO 8 — CICS: QUATRO LETRAS, MUITAS PORTAS
Nosso COBOL PAY001 não precisa ser executado diretamente pelo usuário.
Pode estar associado a uma transação CICS.
Imagine:
PAY9O fluxo:
USER
|
v
PAY9
|
v
PAY001
|
v
DB2
|
v
CUSTOMER TABLEAgora pense como auditor.
Você procura:
Quem possui UPDATE em CUSTOMER?Mas talvez a pergunta realmente interessante seja:
Quem pode executar PAY9?E depois:
O que PAY9 executa?Depois:
Com qual contexto de segurança?Depois:
Quais packages são utilizados?Depois:
Quais objetos esses packages alcançam?Agora temos uma cadeia.
Noir desenha:
USER
↓
CICS TRANSACTION
↓
COBOL PROGRAM
↓
DB2 CONNECTION CONTEXT
↓
PACKAGE
↓
TABLEEssa cadeia é muito mais informativa que uma lista isolada de permissões.
🕸️ CAPÍTULO 9 — O MAINFRAME VIRA UM GRAFO
Agora chegamos à parte divertida.
Imagine representar nosso ambiente como um enorme mapa.
Cada elemento vira um nó:
USER
GROUP
SERVICE ACCOUNT
STARTED TASK
SURROGAT PROFILE
CICS TRANSACTION
CICS PROGRAM
DB2 PACKAGE
DB2 TABLE
DATASET
JCL
LOADLIB
APF LIBRARY
SCHEDULERE as relações tornam-se arestas:
MEMBER_OF
CAN_EXECUTE
CAN_SUBMIT_AS
CAN_UPDATE
CAN_READ
RUNS_AS
CALLS
LOADS_FROM
USES_PACKAGE
CAN_MODIFYEntão:
JOAO
|
| MEMBER_OF
v
GROUP01
|
| CAN_EXECUTE
v
PAY9
|
| STARTS
v
PAY001
|
| USES
v
PKG_PAY
|
| UPDATES
v
CUSTOMERAcabamos de transformar segurança de mainframe em um problema de Graph Theory.
E isso muda tudo.
🧭 CAPÍTULO 10 — O GOOGLE MAPS DOS PRIVILÉGIOS
Noir olha para nosso grafo.
— Quero chegar até CUSTOMER.
O sistema responde:
Você não possui acesso direto.Noir responde:
— Eu não perguntei isso.
Ele pergunta:
Existe algum caminho entre USER01 e CUSTOMER?Agora podemos descobrir:
USER01
↓
GROUPA
↓
TRANSACTION PAY9
↓
PROGRAM PAY001
↓
PACKAGE PKGPAY
↓
CUSTOMERSão cinco saltos.
Em teoria de grafos chamamos cada ligação de edge.
Cada objeto é um node.
Nosso problema passa a ser algo parecido com:
find path USER01 -> CUSTOMEREsse raciocínio lembra ferramentas de análise de caminhos de ataque existentes em outros ecossistemas.
Mas aqui estamos imaginando algo profundamente adaptado ao universo:
z/OS
RACF
JES
CICS
Db2
COBOL
APF
JCL
SMFUm verdadeiro:
Google Maps do privilégio do mainframe.
👻 CAPÍTULO 11 — ORPHANED PRIVILEGE PATH
Noir encontra outra porta.
Nela está escrito:
CREATED: 1999Ele consulta os registros.
1999 — PAY9 criado
2007 — aplicação substituída
2011 — equipe reorganizada
2014 — último uso conhecido
2018 — documentação arquivada
2022 — último especialista aposentado
2026 — PAY9 continua definidoTemos então uma expressão interessante:
Orphaned Privilege Path
Ou:
caminho de privilégio órfão.
É uma capacidade técnica que continua existindo, embora sua justificativa operacional tenha desaparecido ou não esteja mais clara.
Isso é diferente de vulnerabilidade.
Pode não existir bug algum.
O código pode ser maravilhoso.
O problema é:
WHY DOES THIS STILL EXIST?🧟 CAPÍTULO 12 — O ZUMBI NÃO PRECISA TER BUG
Essa distinção merece destaque.
Programa vulnerável:
BUGPrograma privilegiado:
CAPABILITYImagine um programa administrativo chamado:
ACCTMNTEle recebe:
ACCOUNT-NUMBER
NEW-STATUSe executa legitimamente:
UPDATE ACCOUNTO programa funciona perfeitamente.
Nenhum SQL injection.
Nenhum buffer overflow.
Nenhuma corrupção de memória.
Nenhum exploit cinematográfico.
Mas suponha que uma transação antiga ainda permita invocá-lo em condições que ninguém mais documentou.
O problema não é:
software brokenÉ:
legitimate capability
+
unexpected reachabilityEssa diferença é gigantesca para threat modeling.
🔗 CAPÍTULO 13 — PRIVILEGE TRANSITIVITY
Vamos complicar um pouco.
Suponha:
A controla B
B influencia C
C controla DDependendo da semântica dessas relações, talvez A consiga indiretamente influenciar D.
Exemplo:
DEVELOPER
|
| modifies
v
SOURCE
|
| pipeline
v
LOADLIB
|
| loaded by
v
STARTED TASK
|
| accesses
v
CRITICAL RESOURCENosso desenvolvedor talvez não possua:
UPDATE CRITICAL.RESOURCEMas controla algo que eventualmente é executado por uma identidade que possui capacidades relevantes.
Isso significa que devemos investigar não apenas:
WHO CONTROLS RESOURCE?mas também:
WHO CONTROLS THE THING
THAT CONTROLS THE RESOURCE?Noir sorriu.
A dungeon ganhou recursividade.
COBOLzeiros conhecem o perigo de recursividade sem condição de saída.
Auditores também deveriam conhecer.
📡 CAPÍTULO 14 — SMF: AGORA PERGUNTAMOS AO PASSADO
Até agora construímos caminhos possíveis.
Mas mainframes possuem uma característica maravilhosa:
telemetria.
SMF — System Management Facilities — registra enormes quantidades de informações sobre atividade do sistema, dependendo dos registros habilitados e configurações utilizadas.
Isso nos permite imaginar duas dimensões:
POSSIBLEe:
OBSERVEDPor exemplo:
PAY9existe.
Portanto:
POSSIBLE = YESMas encontramos:
LAST OBSERVED USE = 2014Interessante.
Não prova que existe uma vulnerabilidade.
Também não significa automaticamente que podemos apagar PAY9.
Mas cria uma excelente pergunta:
Por que uma capacidade sensível aparentemente sem uso continua instalada?
🔬 CAPÍTULO 15 — O MÉTODO NOIR STARGA
Nosso mestre então apresenta um método defensivo.
Passo 1 — Identifique os recursos críticos
Exemplos:
PAYROLL
CUSTOMER MASTER
SECURITY DATASETS
APF LIBRARIES
CRITICAL DB2 TABLES
PRODUCTION LOADLIBSNão comece tentando modelar o universo inteiro.
Comece pelo tesouro.
Passo 2 — Descubra quem possui acesso direto
Mapeie:
USER
GROUP
SERVICE ACCOUNT
STCPasso 3 — Descubra capacidades executáveis
Procure:
CICS transactions
batch programs
COBOL applications
Db2 packages
procedures
automationPasso 4 — Analise delegação
Inclua:
SURROGAT
service identities
started tasks
scheduler identitiesPasso 5 — Analise influência
Pergunte:
Quem altera JCL?
Quem altera PROCLIB?
Quem altera LOADLIB?
Quem altera configuração?
Quem controla deployment?
Quem altera bibliotecas relevantes?Passo 6 — Correlacione tudo
Agora temos:
IDENTITY
↓
CAPABILITY
↓
EXECUTION CONTEXT
↓
RESOURCEPasso 7 — Acrescente telemetria
Use evidências operacionais disponíveis para descobrir:
last use
frequency
source
execution contextPasso 8 — Investigue órfãos
Procure combinações como:
HIGH PRIVILEGE
+
LOW USAGE
+
OLD COMPONENT
+
UNKNOWN OWNER
+
UNCLEAR BUSINESS JUSTIFICATIONIsso não é sentença automática de remoção.
É uma fila maravilhosa para investigação.
📊 CAPÍTULO 16 — UM MODELO DE RISCO MAIS INTELIGENTE
Podemos imaginar uma classificação interna baseada em dimensões.
Não como verdade matemática, mas como priorização operacional:
Risk =
Privilege
× Reachability
× Exposure
× Obsolescence
× Ownership UncertaintyConsidere dois objetos.
Objeto A
RACF SPECIAL USER
MFA
named owner
daily use
monitored
recertifiedObjeto B
CICS transaction
created 1998
privileged backend operation
unknown owner
rarely observed
legacy service identity
poor documentationQual deles merece investigação?
Talvez ambos.
Mas por razões completamente diferentes.
A lição é não assumir que:
VISIBLE PRIVILEGEé necessariamente nosso único problema.
🧩 CAPÍTULO 17 — ACCESS NÃO É CAPABILITY
Aqui está uma das mensagens mais importantes deste artigo.
Considere:
USER01 -> CUSTOMER TABLESem acesso.
Mas:
USER01
↓
PAY9
↓
PAY001
↓
PKGPAY
↓
CUSTOMER TABLEAgora existe uma capacidade.
Portanto:
ACCESS ≠ CAPABILITYE mais:
PRIVILEGE ≠ USER ATTRIBUTEUma forma útil de pensar seria:
PRIVILEGE = REACHABLE CAPABILITYNão como definição formal universal, mas como modelo mental de investigação.
Isso muda a pergunta do auditor.
De:
WHO HAS ACCESS?para:
WHO CAN REACH THE CAPABILITY?🥚 CAPÍTULO 18 — EASTER EGG: A TRANSAÇÃO N0IR
Durante a investigação, nosso COBOLzeiro encontra:
TRANSACTION: N0IR
PROGRAM: HIDDENDGEle pergunta:
— Noir, foi você?
— Evidentemente não.
— Mas o programa foi criado ontem.
— Coincidência.
Dentro do fonte:
01 WS-DUNGEON-LEVEL PIC 9(02) VALUE 01.
PERFORM UNTIL WS-DUNGEON-LEVEL > 99
DISPLAY 'THERE IS ALWAYS ANOTHER PATH'
ADD 1 TO WS-DUNGEON-LEVEL
END-PERFORM.Noir saiu andando.
O COBOLzeiro decidiu não perguntar mais nada.
🧐 CAPÍTULO 19 — CURIOSIDADE: O LEGADO PODE SER FORTE JUSTAMENTE PORQUE FUNCIONA
Existe uma ironia maravilhosa no mainframe.
Alguns programas permanecem décadas em produção justamente porque:
funcionam.
Um COBOL escrito em 1995 pode continuar executando perfeitamente.
Isso é uma enorme virtude da plataforma.
Mas longevidade cria uma consequência interessante para segurança.
O código pode sobreviver a:
desenvolvedores
gerentes
fornecedores
documentação
processos
interfaces
arquiteturasOu seja:
software lifetime > organizational memoryQuando isso acontece, nasce o verdadeiro legado perigoso.
Não é necessariamente código antigo.
É:
código cuja capacidade técnica sobreviveu à memória institucional sobre por que aquela capacidade existe.
Essa definição é muito mais útil.
🧭 CAPÍTULO 20 — A DUNGEON COMPLETA
Noir finalmente abre o mapa.
Ele ocupa a parede inteira:
USER
|
MEMBER_OF
|
GROUP
|
+----------------+----------------+
| |
SURROGAT CICS TRAN
| |
SERVICE ID PROGRAM
| |
JOB DB2 PACKAGE
| |
PROGRAM TABLE
|
LOADLIB
|
STARTED TASK
|
SYSTEM RESOURCEAgora entendemos por que analisar somente ACLs individuais não basta.
O sistema é um grafo de confiança.
Cada relacionamento pode aumentar ou restringir capacidade.
Cada salto precisa ser interpretado segundo sua semântica real.
Não basta simplesmente dizer:
A -> B -> Ce concluir que A controla C.
Precisamos entender o significado de cada aresta.
Mas uma vez que fazemos isso, começamos a enxergar coisas que relatórios isolados dificilmente mostram.
☕ EPÍLOGO — O MONSTRO NÃO ESTAVA NA SALA DO RACF
Horas depois, Noir voltou à primeira porta.
PAY9A investigação mostrou que ela pertencia a uma aplicação antiga.
O usuário comum não tinha acesso direto às tabelas sensíveis.
Tudo parecia correto quando observado separadamente.
Mas a arquitetura contava outra história.
Havia:
USER
↓
CICS TRANSACTION
↓
COBOL PROGRAM
↓
DB2 PACKAGE
↓
SENSITIVE DATANão encontramos necessariamente um invasor.
Não encontramos necessariamente uma vulnerabilidade.
Encontramos algo mais importante para um trabalho preventivo:
uma pergunta que ninguém fazia havia anos.
Essa capacidade ainda deveria existir?
Essa talvez seja a essência da segurança em sistemas com quarenta anos de história.
Não basta perguntar:
Quem possui a chave?Precisamos perguntar:
Quem consegue abrir a porta?Depois:
Quem consegue mandar alguém abrir?Depois:
Quem consegue modificar a fechadura?Depois:
Quem consegue modificar o programa
que controla a fechadura?E finalmente:
POR QUE ESSA PORTA AINDA EXISTE?Noir Starga fechou o terminal.
O programador COBOL perguntou:
— Então quem é mais perigoso? O usuário privilegiado ou o programa privilegiado esquecido?
Noir pegou seu café.
— O usuário privilegiado nós sabemos procurar.
Ele apontou para PAY9.
— Esse aí ficou vinte anos esperando alguém lembrar de perguntar.
Na tela apareceu:
READYE, escondida em algum canto do sysplex, uma transação criada antes de alguns membros da equipe nascerem continuava esperando pacientemente pelo próximo comando.
Porque mainframe não esquece só porque nós esquecemos.
E essa, jovem COBOLzeiro, é justamente a razão pela qual segurança de sistemas legados não pode terminar em:
WHO HAS ACCESS?Ela precisa continuar até:
WHO CAN REACH WHAT?
|
v
THROUGH WHICH PATH?
|
v
UNDER WHOSE AUTHORITY?
|
v
USING WHICH PROGRAM?
|
v
AND WHY DOES IT STILL EXIST?☕ Bem-vindo à dungeon dos privilégios.
No próximo andar há RACF, CICS, Db2, APF, SURROGAT, started tasks, service accounts, JCL, SMF e quarenta anos de história corporativa esperando para serem transformados em um grafo.
E Noir já encontrou a escada.